|
|
@@ -1,244 +1,600 @@
|
|
|
<!doctype html>
|
|
|
-<html lang="en">
|
|
|
+<html lang="zh">
|
|
|
<head>
|
|
|
- <meta charset="UTF-8">
|
|
|
- <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
|
|
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
|
- <title>MES可视化大屏</title>
|
|
|
- <link rel="stylesheet" href="${ctxStatic}/bootstrap/css/bootstrap.min.css">
|
|
|
- <link rel="stylesheet" href="${ctxStatic}/screen/style.css">
|
|
|
- <style>
|
|
|
- .oprnobox{
|
|
|
- position: absolute;
|
|
|
- /*width: 930px;*/
|
|
|
- height: 688px;
|
|
|
- z-index: 100;
|
|
|
- }
|
|
|
- .oprnobox.box1{
|
|
|
- top: 171px;
|
|
|
- left: 25px;
|
|
|
- right: 25px;
|
|
|
- }
|
|
|
- .oprnobox.box2{
|
|
|
- top: 171px;
|
|
|
- right: 25px;
|
|
|
- }
|
|
|
- .oprnobox-header{
|
|
|
- width: 100%;
|
|
|
- height: 58px;
|
|
|
- line-height: 58px;
|
|
|
- overflow: hidden;
|
|
|
- background-color: rgba(20, 55, 120, 0.8);
|
|
|
- font-size: 20px;
|
|
|
- color: #008FFD;
|
|
|
- font-weight: bold;
|
|
|
- text-align: center;
|
|
|
- }
|
|
|
- .oprnobox-header .oprno-name{
|
|
|
- width: 25%;
|
|
|
- float: left;
|
|
|
- }
|
|
|
- .oprnobox-header .oprno-plan{
|
|
|
- width: 15%;
|
|
|
- float: left;
|
|
|
- }
|
|
|
- .oprnobox-header .oprno-actual{
|
|
|
- width: 15%;
|
|
|
- float: left;
|
|
|
- }
|
|
|
- .oprnobox-header .oprno-ng{
|
|
|
- width: 15%;
|
|
|
- float: left;
|
|
|
- }
|
|
|
- .oprnobox-header .oprno-rate{
|
|
|
- width: 15%;
|
|
|
- float: left;
|
|
|
- }
|
|
|
- .oprnobox-header .oprno-quality{
|
|
|
- width: 15%;
|
|
|
- float: left;
|
|
|
- }
|
|
|
-
|
|
|
- .oprnobox-list{
|
|
|
- width: 100%;
|
|
|
- height: 80px;
|
|
|
- line-height: 80px;
|
|
|
- overflow: hidden;
|
|
|
- font-size: 28px;
|
|
|
- text-align: center;
|
|
|
- font-family: FZChaoCuHei-M10S;
|
|
|
- font-weight: 400;
|
|
|
- color: #FFFFFF;
|
|
|
- background-image: url("${ctxStatic}/screen/imgs/rbg.png");
|
|
|
- background-size: 100% 100%;
|
|
|
- background-repeat: no-repeat;
|
|
|
- }
|
|
|
- .oprnobox-list .oprno-name{
|
|
|
- width: 25%;
|
|
|
- height: 80px;
|
|
|
- float: left;
|
|
|
- }
|
|
|
- .oprnobox-list .oprno-plan{
|
|
|
- width: 15%;
|
|
|
- height: 80px;
|
|
|
- float: left;
|
|
|
- }
|
|
|
- .oprnobox-list .oprno-actual{
|
|
|
- width: 15%;
|
|
|
- height: 80px;
|
|
|
- float: left;
|
|
|
- }
|
|
|
- .oprnobox-list .oprno-ng{
|
|
|
- width: 15%;
|
|
|
- height: 80px;
|
|
|
- float: left;
|
|
|
- }
|
|
|
- .oprnobox-list .oprno-rate{
|
|
|
- width: 15%;
|
|
|
- height: 80px;
|
|
|
- float: left;
|
|
|
- }
|
|
|
- .oprnobox-list .oprno-quality{
|
|
|
- width: 15%;
|
|
|
- height: 80px;
|
|
|
- float: left;
|
|
|
- }
|
|
|
- </style>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <title>MES可视化大屏</title>
|
|
|
+ <script src="${ctxStatic}/jquery-1.11.3.min.js"></script>
|
|
|
+ <style>
|
|
|
+ * { margin: 0; padding: 0; box-sizing: border-box; }
|
|
|
+ html, body {
|
|
|
+ width: 100%; height: 100%;
|
|
|
+ background: #060e1f; overflow: hidden;
|
|
|
+ }
|
|
|
+ #screen {
|
|
|
+ position: absolute;
|
|
|
+ top: 0; left: 0;
|
|
|
+ width: 1920px; height: 1080px;
|
|
|
+ transform-origin: top left;
|
|
|
+ background: #0a1628;
|
|
|
+ color: #fff;
|
|
|
+ font-family: 'Microsoft YaHei', sans-serif;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 四角装饰 */
|
|
|
+ .corner { position: absolute; width: 26px; height: 26px; z-index: 999; }
|
|
|
+ .corner-tl { top: 8px; left: 8px; border-top: 2px solid #00d4ff; border-left: 2px solid #00d4ff; }
|
|
|
+ .corner-tr { top: 8px; right: 8px; border-top: 2px solid #00d4ff; border-right: 2px solid #00d4ff; }
|
|
|
+ .corner-bl { bottom: 8px; left: 8px; border-bottom: 2px solid #00d4ff; border-left: 2px solid #00d4ff; }
|
|
|
+ .corner-br { bottom: 8px; right: 8px; border-bottom: 2px solid #00d4ff; border-right: 2px solid #00d4ff; }
|
|
|
+
|
|
|
+ /* ===== 顶部标题栏 ===== */
|
|
|
+ .top-bar {
|
|
|
+ position: absolute;
|
|
|
+ top: 0; left: 0; right: 0; height: 76px;
|
|
|
+ background: linear-gradient(180deg, rgba(0,60,120,.6) 0%, transparent 100%);
|
|
|
+ border-bottom: 1px solid rgba(0,212,255,.2);
|
|
|
+ }
|
|
|
+ .top-bar::after {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0; left: 8%; right: 8%; height: 1px;
|
|
|
+ background: linear-gradient(90deg, transparent, #00d4ff 30%, #00d4ff 70%, transparent);
|
|
|
+ }
|
|
|
+ .top-date {
|
|
|
+ position: absolute; left: 32px; top: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ font-size: 17px; color: #00d4ff; letter-spacing: 1px;
|
|
|
+ }
|
|
|
+ .top-title {
|
|
|
+ position: absolute; left: 50%; top: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ font-size: 38px; font-weight: 700; letter-spacing: 6px;
|
|
|
+ color: #fff; white-space: nowrap;
|
|
|
+ }
|
|
|
+ .top-title::before, .top-title::after {
|
|
|
+ content: '◆';
|
|
|
+ position: absolute; top: 50%; transform: translateY(-50%);
|
|
|
+ color: #00d4ff; font-size: 14px;
|
|
|
+ }
|
|
|
+ .top-title::before { left: -50px; }
|
|
|
+ .top-title::after { right: -50px; }
|
|
|
+ .top-clock {
|
|
|
+ position: absolute; right: 32px; top: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ font-size: 30px; color: #00d4ff;
|
|
|
+ font-family: 'Courier New', monospace; letter-spacing: 3px;
|
|
|
+ display: flex; align-items: center; gap: 12px;
|
|
|
+ }
|
|
|
+ .live-dot {
|
|
|
+ width: 10px; height: 10px; border-radius: 50%;
|
|
|
+ background: #00e676;
|
|
|
+ box-shadow: 0 0 10px #00e676;
|
|
|
+ animation: blink 1.2s infinite;
|
|
|
+ }
|
|
|
+ @keyframes blink { 0%,100%{opacity:1} 50%{opacity:.15} }
|
|
|
+
|
|
|
+ /* ===== 主表格区 ===== */
|
|
|
+ .body-area {
|
|
|
+ position: absolute;
|
|
|
+ top: 90px; left: 14px; right: 14px; bottom: 14px;
|
|
|
+ }
|
|
|
+ .panel {
|
|
|
+ background: rgba(13,33,68,.85);
|
|
|
+ border: 1px solid rgba(0,212,255,.18);
|
|
|
+ border-radius: 4px;
|
|
|
+ position: relative;
|
|
|
+ height: 100%;
|
|
|
+ display: flex; flex-direction: column;
|
|
|
+ }
|
|
|
+ .panel::before {
|
|
|
+ content: ''; position: absolute;
|
|
|
+ top: -1px; left: -1px; width: 12px; height: 12px;
|
|
|
+ border-top: 2px solid #00d4ff; border-left: 2px solid #00d4ff;
|
|
|
+ }
|
|
|
+ .panel::after {
|
|
|
+ content: ''; position: absolute;
|
|
|
+ bottom: -1px; right: -1px; width: 12px; height: 12px;
|
|
|
+ border-bottom: 2px solid #00d4ff; border-right: 2px solid #00d4ff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .panel-hd {
|
|
|
+ font-size: 16px; color: #00d4ff;
|
|
|
+ padding: 14px 18px 8px;
|
|
|
+ display: flex; align-items: center; gap: 8px;
|
|
|
+ letter-spacing: 1px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+ .panel-hd::before {
|
|
|
+ content: '';
|
|
|
+ width: 4px; height: 18px;
|
|
|
+ background: #00d4ff; border-radius: 2px;
|
|
|
+ box-shadow: 0 0 6px #00d4ff;
|
|
|
+ }
|
|
|
+ .panel-hd-deco { font-size: 12px; color: #2a4a6a; margin-left: 6px; }
|
|
|
+
|
|
|
+ /* ===== 左右双列 ===== */
|
|
|
+ .table-scroll {
|
|
|
+ flex: 1; overflow: hidden;
|
|
|
+ display: flex;
|
|
|
+ margin-top: 8px;
|
|
|
+ }
|
|
|
+ .table-col {
|
|
|
+ flex: 1; min-width: 0;
|
|
|
+ display: flex; flex-direction: column;
|
|
|
+ }
|
|
|
+ .table-col + .table-col { border-left: 1px solid rgba(0,212,255,.25); }
|
|
|
+
|
|
|
+ /* 产品大标题 */
|
|
|
+ .col-title {
|
|
|
+ background: rgba(95,221,161,.15);
|
|
|
+ color: #5fdda1;
|
|
|
+ font-size: 22px; font-weight: 700;
|
|
|
+ text-align: center; padding: 14px 0;
|
|
|
+ letter-spacing: 4px;
|
|
|
+ border-bottom: 1px solid rgba(95,221,161,.3);
|
|
|
+ text-shadow: 0 0 8px rgba(95,221,161,.5);
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+ .table-col.col-orange .col-title {
|
|
|
+ background: rgba(255,176,69,.15); color: #ffb045;
|
|
|
+ border-bottom-color: rgba(255,176,69,.3);
|
|
|
+ text-shadow: 0 0 8px rgba(255,176,69,.5);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ===== 表头行(按列分组)===== */
|
|
|
+ .row-head {
|
|
|
+ display: flex;
|
|
|
+ background: #0c2a5a;
|
|
|
+ color: #00d4ff;
|
|
|
+ border-bottom: 1px solid rgba(0,212,255,.3);
|
|
|
+ letter-spacing: 1px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ height: 64px;
|
|
|
+ }
|
|
|
+ .row-head > div {
|
|
|
+ border-left: 1px solid rgba(0,212,255,.18);
|
|
|
+ }
|
|
|
+ .row-head > div:first-child { border-left: none; }
|
|
|
+
|
|
|
+ /* 单格列:贯穿整个表头高度、上下居中 */
|
|
|
+ .hcell-single {
|
|
|
+ display: flex; align-items: center; justify-content: center;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 15px; font-weight: 600;
|
|
|
+ padding: 0 4px;
|
|
|
+ line-height: 1.2;
|
|
|
+ }
|
|
|
+ /* 班次分组块:上半班次名,下半实际/不良 */
|
|
|
+ .hcell-group {
|
|
|
+ display: flex; flex-direction: column;
|
|
|
+ }
|
|
|
+ .hcell-group .grp-title {
|
|
|
+ height: 34px;
|
|
|
+ display: flex; align-items: center; justify-content: center;
|
|
|
+ font-size: 15px; font-weight: 600;
|
|
|
+ color: #ffd479;
|
|
|
+ border-bottom: 1px solid rgba(0,212,255,.2);
|
|
|
+ }
|
|
|
+ .hcell-group .grp-subs {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ }
|
|
|
+ .hcell-group .grp-subs > div {
|
|
|
+ flex: 1;
|
|
|
+ display: flex; align-items: center; justify-content: center;
|
|
|
+ font-size: 13px; font-weight: 600;
|
|
|
+ color: #7fc8e8;
|
|
|
+ }
|
|
|
+ .hcell-group .grp-subs > div + div {
|
|
|
+ border-left: 1px solid rgba(0,212,255,.12);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 数据行容器:撑满列剩余高度,行均分 */
|
|
|
+ .body-rows {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ===== 数据行 ===== */
|
|
|
+ .row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ flex: 1 1 0;
|
|
|
+ min-height: 0;
|
|
|
+ border-bottom: 1px solid rgba(255,255,255,.05);
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .row.odd { background: rgba(8,22,50,1); }
|
|
|
+ .row.even { background: rgba(18,38,72,1); }
|
|
|
+ .row:hover { background: rgba(0,212,255,.12) !important; }
|
|
|
+
|
|
|
+ /* 不良预警行:左侧红条 + 淡红底 */
|
|
|
+ .row.warn {
|
|
|
+ background: rgba(255,60,80,.14) !important;
|
|
|
+ box-shadow: inset 4px 0 0 #ff3c50;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 列宽(8 列)*/
|
|
|
+ .c-name { width: 168px; flex-shrink: 0; }
|
|
|
+ .c-oprno { width: 150px; flex-shrink: 0; }
|
|
|
+ .c-num { flex: 1; min-width: 0; }
|
|
|
+ .c-group { flex: 2; min-width: 0; }
|
|
|
+ .c-total { width: 96px; flex-shrink: 0; }
|
|
|
+ .c-ngtot { width: 80px; flex-shrink: 0; }
|
|
|
+
|
|
|
+ .cell {
|
|
|
+ text-align: center;
|
|
|
+ padding: 0 4px;
|
|
|
+ border-left: 1px solid rgba(255,255,255,.04);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 工序名称 */
|
|
|
+ .cell-name {
|
|
|
+ text-align: left;
|
|
|
+ font-size: 16px; font-weight: 600;
|
|
|
+ color: #e0e8f0;
|
|
|
+ padding-left: 14px;
|
|
|
+ letter-spacing: 1px;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ border-left: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 工位号列:多个工位横排,放不下自动折行 */
|
|
|
+ .cell-oprno {
|
|
|
+ display: flex; flex-direction: row;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ align-items: center; justify-content: center;
|
|
|
+ gap: 2px 6px;
|
|
|
+ font-family: 'Courier New', monospace;
|
|
|
+ font-size: 13px; color: #9aabbc;
|
|
|
+ max-height: 56px; overflow: hidden;
|
|
|
+ padding: 0 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 数字单元 */
|
|
|
+ .cell-num {
|
|
|
+ font-family: 'Courier New', monospace;
|
|
|
+ font-size: 30px; font-weight: 700;
|
|
|
+ }
|
|
|
+ .num-ok-kb { color: #5fdda1; }
|
|
|
+ .num-ok-ka { color: #ffb045; }
|
|
|
+ .num-ng { color: #ff5e6c; }
|
|
|
+ .num-zero { color: #243042; }
|
|
|
+
|
|
|
+ /* 夜班数字统一淡白蓝(对两种产品都清晰区分)*/
|
|
|
+ .row .c-num.night .cell-num.num-ok-kb,
|
|
|
+ .row .c-num.night .cell-num.num-ok-ka {
|
|
|
+ color: #cfdef5;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 当前班次:表头加亮,数据格不加底色避免视觉割裂 */
|
|
|
+ /* 非当前班次列轻微弱化(仍清晰可读)*/
|
|
|
+ .row .c-num.inactive { opacity: .8; }
|
|
|
+ /* 表头当前班次分组高亮 */
|
|
|
+ .hcell-group.active .grp-title { color: #00e676; }
|
|
|
+ .hcell-group.inactive { opacity: .85; }
|
|
|
+
|
|
|
+ /* 产能合计大数字 */
|
|
|
+ .cell-total {
|
|
|
+ font-size: 27px; font-weight: 900;
|
|
|
+ font-family: 'Arial Black', 'Microsoft YaHei', sans-serif;
|
|
|
+ color: #5fdda1;
|
|
|
+ letter-spacing: 1px;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+ .table-col.col-orange .cell-total {
|
|
|
+ color: #ffb045;
|
|
|
+ }
|
|
|
+ /* 不良合计 */
|
|
|
+ .cell-ngtot {
|
|
|
+ font-size: 24px; font-weight: 900;
|
|
|
+ font-family: 'Arial Black', 'Microsoft YaHei', sans-serif;
|
|
|
+ color: #ff5e6c;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+ .cell-ngtot.zero { color: #2a3a4a; }
|
|
|
+
|
|
|
+ /* 补齐空行:保持两列等高 */
|
|
|
+ .row-pad {
|
|
|
+ flex: 1 1 0;
|
|
|
+ min-height: 0;
|
|
|
+ border-bottom: 1px solid rgba(255,255,255,.05);
|
|
|
+ }
|
|
|
+
|
|
|
+ .empty-tip {
|
|
|
+ text-align: center; padding: 80px 0;
|
|
|
+ color: #2a3a4a; font-size: 16px;
|
|
|
+ }
|
|
|
+ .refresh-tip {
|
|
|
+ text-align: center; font-size: 12px;
|
|
|
+ color: #2a3a4a; padding: 8px 0; letter-spacing: 1px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
</head>
|
|
|
-<body id="app">
|
|
|
-<div class="screenbg">
|
|
|
- <img class="bg1" src="${ctxStatic}/screen/imgs/bg.png" alt="">
|
|
|
- <img class="bg2" style="display: none;" src="${ctxStatic}/screen/imgs/bg2.png" alt="">
|
|
|
-</div>
|
|
|
-<div class="screenbox1">
|
|
|
- <div class="screenmain">
|
|
|
- <div class="screen-title">MES系统生产数据大屏</div>
|
|
|
-
|
|
|
- <div class="oprnobox box1">
|
|
|
- <div class="oprnobox-header">
|
|
|
- <div class="oprno-name">工序名称</div>
|
|
|
- <div class="oprno-plan">计划投产数</div>
|
|
|
- <div class="oprno-actual">实际产出数</div>
|
|
|
- <div class="oprno-ng">不良数</div>
|
|
|
- <div class="oprno-rate">达成率(%)</div>
|
|
|
- <div class="oprno-quality">合格率(%)</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div id="numbox">
|
|
|
- <!--<div class="oprnobox-list">
|
|
|
- <div class="oprno-name">CMT</div>
|
|
|
- <div class="oprno-plan">180</div>
|
|
|
- <div class="oprno-actual">180</div>
|
|
|
- <div class="oprno-ng">0</div>
|
|
|
- <div class="oprno-rate">100%</div>
|
|
|
- <div class="oprno-quality">100%</div>
|
|
|
- </div>-->
|
|
|
- </div>
|
|
|
-
|
|
|
- </div>
|
|
|
-
|
|
|
- </div>
|
|
|
+<body>
|
|
|
+
|
|
|
+<div id="screen">
|
|
|
+ <div class="corner corner-tl"></div>
|
|
|
+ <div class="corner corner-tr"></div>
|
|
|
+ <div class="corner corner-bl"></div>
|
|
|
+ <div class="corner corner-br"></div>
|
|
|
+
|
|
|
+ <!-- 顶部 -->
|
|
|
+ <div class="top-bar">
|
|
|
+ <div class="top-date" id="topDate"></div>
|
|
|
+ <div class="top-title">MES系统生产数据大屏</div>
|
|
|
+ <div class="top-clock"><span id="topClock"></span><div class="live-dot"></div></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 主体 -->
|
|
|
+ <div class="body-area">
|
|
|
+ <div class="panel">
|
|
|
+ <div class="panel-hd">工序计件明细<span class="panel-hd-deco">// // //</span></div>
|
|
|
+ <div class="table-scroll">
|
|
|
+ <!-- 左 KA64 -->
|
|
|
+ <div class="table-col" id="colKb">
|
|
|
+ <div class="col-title">+KA64</div>
|
|
|
+ <div class="row-head">
|
|
|
+ <div class="hcell-single c-name">工序名称</div>
|
|
|
+ <div class="hcell-single c-oprno">工位号</div>
|
|
|
+ <div class="hcell-group c-group">
|
|
|
+ <div class="grp-title">白班</div>
|
|
|
+ <div class="grp-subs"><div>实际</div><div>不良</div></div>
|
|
|
+ </div>
|
|
|
+ <div class="hcell-group c-group">
|
|
|
+ <div class="grp-title">夜班</div>
|
|
|
+ <div class="grp-subs"><div>实际</div><div>不良</div></div>
|
|
|
+ </div>
|
|
|
+ <div class="hcell-single c-total">产能合计</div>
|
|
|
+ <div class="hcell-single c-ngtot">不良合计</div>
|
|
|
+ </div>
|
|
|
+ <div class="body-rows" id="bodyKb"></div>
|
|
|
+ </div>
|
|
|
+ <!-- 右 KB23 -->
|
|
|
+ <div class="table-col col-orange" id="colKa">
|
|
|
+ <div class="col-title">+KB23</div>
|
|
|
+ <div class="row-head">
|
|
|
+ <div class="hcell-single c-name">工序名称</div>
|
|
|
+ <div class="hcell-single c-oprno">工位号</div>
|
|
|
+ <div class="hcell-group c-group">
|
|
|
+ <div class="grp-title">白班</div>
|
|
|
+ <div class="grp-subs"><div>实际</div><div>不良</div></div>
|
|
|
+ </div>
|
|
|
+ <div class="hcell-group c-group">
|
|
|
+ <div class="grp-title">夜班</div>
|
|
|
+ <div class="grp-subs"><div>实际</div><div>不良</div></div>
|
|
|
+ </div>
|
|
|
+ <div class="hcell-single c-total">产能合计</div>
|
|
|
+ <div class="hcell-single c-ngtot">不良合计</div>
|
|
|
+ </div>
|
|
|
+ <div class="body-rows" id="bodyKa"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="refresh-tip">数据每30秒自动刷新</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
-<script src="${ctxStatic}/jquery-1.11.3.min.js"></script>
|
|
|
-<!--<script src="${ctxStatic}/common/vue2.7.14.min.js"></script>-->
|
|
|
<script>
|
|
|
- let lists = [];
|
|
|
- let info = null;
|
|
|
- let curIdx = 0;
|
|
|
-
|
|
|
- $(window).resize(function(){
|
|
|
- location.reload()
|
|
|
- });
|
|
|
-
|
|
|
- $(function () {
|
|
|
- changeZoom();
|
|
|
-
|
|
|
- getData();
|
|
|
-
|
|
|
- setInterval(function () {
|
|
|
- getData();
|
|
|
- },1000*60*2);
|
|
|
-
|
|
|
- setInterval(function () {
|
|
|
- formatData();
|
|
|
- },1000*10);
|
|
|
- });
|
|
|
-
|
|
|
- function getData() {
|
|
|
- let url = "/js/a/mes/mesProduct/screenData";
|
|
|
- $.post(url,function (ret) {
|
|
|
- lists = ret.data;
|
|
|
- curIdx = 0;
|
|
|
- formatData();
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- function formatData(){
|
|
|
- let str = '';
|
|
|
- const pageSize = 7; // 每页显示7条
|
|
|
- const totalCount = Object.keys(lists).length;
|
|
|
- const totalPages = Math.ceil(totalCount / pageSize);
|
|
|
-
|
|
|
- // 计算当前页的起始和结束索引
|
|
|
- const startIdx = curIdx * pageSize;
|
|
|
- const endIdx = Math.min(startIdx + pageSize, totalCount);
|
|
|
-
|
|
|
- let i = 0;
|
|
|
- for (let o in lists) {
|
|
|
- if(i >= startIdx && i < endIdx){
|
|
|
- let item = lists[o];
|
|
|
-
|
|
|
- // 计算不良数
|
|
|
- let ngCount = (item.dayCountTotal || 0) - (item.dayCountOk || 0);
|
|
|
-
|
|
|
- // 计算达成率
|
|
|
- let achieveRate = '0';
|
|
|
- if(item.planCount && item.planCount > 0){
|
|
|
- achieveRate = ((item.dayCountTotal || 0) / item.planCount * 100).toFixed(1);
|
|
|
- }
|
|
|
-
|
|
|
- // 计算合格率
|
|
|
- let qualityRate = '100';
|
|
|
- if(item.dayCountTotal && item.dayCountTotal > 0){
|
|
|
- qualityRate = ((item.dayCountOk || 0) / item.dayCountTotal * 100).toFixed(1);
|
|
|
- }
|
|
|
-
|
|
|
- str += '<div class="oprnobox-list">';
|
|
|
- str += '<div class="oprno-name">'+(item.title || '')+'</div>';
|
|
|
- str += '<div class="oprno-plan">'+(item.planCount || 0)+'</div>';
|
|
|
- str += '<div class="oprno-actual">'+(item.dayCountTotal || 0)+'</div>';
|
|
|
- str += '<div class="oprno-ng">'+ngCount+'</div>';
|
|
|
- str += '<div class="oprno-rate">'+achieveRate+'%</div>';
|
|
|
- str += '<div class="oprno-quality">'+qualityRate+'%</div>';
|
|
|
- str += '</div>';
|
|
|
- }
|
|
|
- i++;
|
|
|
- }
|
|
|
-
|
|
|
- $("#numbox").html(str);
|
|
|
-
|
|
|
- // 切换到下一页
|
|
|
- curIdx++;
|
|
|
- if(curIdx >= totalPages){
|
|
|
- curIdx = 0;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- function changeZoom() {
|
|
|
- var wb = $(window).width() / 1920;
|
|
|
- var hb = $(window).height() / 1080;
|
|
|
- if (wb >= hb) {
|
|
|
- $('body').css({
|
|
|
- 'zoom': hb,
|
|
|
- });
|
|
|
- } else {
|
|
|
- $('body').css({
|
|
|
- 'zoom': wb,
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
+(function(){
|
|
|
+
|
|
|
+ var DEFAULT_PREFIXES = ['+KA64', '+KB23'];
|
|
|
+
|
|
|
+ /* ---- 当前班次判断(白班 08:30-20:30,否则夜班)---- */
|
|
|
+ function currentShift(){
|
|
|
+ var d = new Date();
|
|
|
+ var mins = d.getHours() * 60 + d.getMinutes();
|
|
|
+ return (mins >= 510 && mins < 1230) ? 'day' : 'night'; // 510=08:30, 1230=20:30
|
|
|
+ }
|
|
|
+ /* 给表头标记当前班次 */
|
|
|
+ function markHeaderShift(){
|
|
|
+ var sh = currentShift();
|
|
|
+ $('.hcell-group').each(function(i){
|
|
|
+ // 每列两个分组块:偶数索引白班,奇数夜班
|
|
|
+ var blockShift = (i % 2 === 0) ? 'day' : 'night';
|
|
|
+ $(this).removeClass('active inactive')
|
|
|
+ .addClass(blockShift === sh ? 'active' : 'inactive');
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ---- 缩放适配 ---- */
|
|
|
+ function fitScreen(){
|
|
|
+ var sx = window.innerWidth / 1920;
|
|
|
+ var sy = window.innerHeight / 1080;
|
|
|
+ var s = Math.min(sx, sy);
|
|
|
+ var el = document.getElementById('screen');
|
|
|
+ el.style.transform = 'scale(' + s + ')';
|
|
|
+ el.style.left = ((window.innerWidth - 1920 * s) / 2) + 'px';
|
|
|
+ el.style.top = ((window.innerHeight - 1080 * s) / 2) + 'px';
|
|
|
+ }
|
|
|
+ fitScreen();
|
|
|
+ window.addEventListener('resize', fitScreen);
|
|
|
+
|
|
|
+ /* ---- 时钟 ---- */
|
|
|
+ var DAYS = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'];
|
|
|
+ function pad(n){ return String(n).padStart(2,'0'); }
|
|
|
+ function updateClock(){
|
|
|
+ var d = new Date();
|
|
|
+ $('#topDate').text(d.getFullYear()+'-'+pad(d.getMonth()+1)+'-'+pad(d.getDate())+' '+DAYS[d.getDay()]);
|
|
|
+ $('#topClock').text(pad(d.getHours())+':'+pad(d.getMinutes())+':'+pad(d.getSeconds()));
|
|
|
+ }
|
|
|
+ updateClock();
|
|
|
+ setInterval(updateClock, 1000);
|
|
|
+
|
|
|
+ /* ---- 分页 ---- */
|
|
|
+ var kbPages = [], kaPages = [];
|
|
|
+ var kbIdx = 0, kaIdx = 0;
|
|
|
+ var kbTimer = null, kaTimer = null;
|
|
|
+ var PAGE_INTERVAL = 5000;
|
|
|
+ var MAX_GROUPS_PER_PAGE = 8; // 每页最多工序数(行会自适应撑满高度)
|
|
|
+ var MIN_GROUPS_PER_PAGE = 4;
|
|
|
+ var ONE_PAGE_LIMIT = 8; // 工序数 <= 此值才一页显示,否则分页
|
|
|
+
|
|
|
+ function loadPiece(){
|
|
|
+ $.get('/js/a/mes/mesProduct/screenPieceData', function(data){
|
|
|
+ if(!data || data.result != 1) { console.warn('piece bad', data); return; }
|
|
|
+ var groups = data.groups || [];
|
|
|
+ var prefixes = (data.prefixes && data.prefixes.length) ? data.prefixes : DEFAULT_PREFIXES;
|
|
|
+ var p0 = prefixes[0], p1 = prefixes[1];
|
|
|
+
|
|
|
+ // 两列分别过滤出有数据的工序
|
|
|
+ var kbGroups = filterGroups(groups, p0);
|
|
|
+ var kaGroups = filterGroups(groups, p1);
|
|
|
+
|
|
|
+ // 统一分页:按两列中较多的行数决定每页行数和页数,保证两列每页行数一致、同步翻页
|
|
|
+ var maxCount = Math.max(kbGroups.length, kaGroups.length);
|
|
|
+ var perPage = calcPerPage(maxCount);
|
|
|
+ kbPages = paginate(kbGroups, perPage);
|
|
|
+ kaPages = paginate(kaGroups, perPage);
|
|
|
+
|
|
|
+ if(kbIdx >= kbPages.length) kbIdx = 0;
|
|
|
+ if(kaIdx >= kaPages.length) kaIdx = 0;
|
|
|
+
|
|
|
+ $('#bodyKb').html(renderPage(kbPages[kbIdx] || [], p0, 'kb'));
|
|
|
+ $('#bodyKa').html(renderPage(kaPages[kaIdx] || [], p1, 'ka'));
|
|
|
+ padColumns();
|
|
|
+
|
|
|
+ startTimers(p0, p1);
|
|
|
+ }).fail(function(xhr){ console.error('piece fail', xhr.status); });
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 两列行数补齐:给少的一列底部加空行(页内行数一致)*/
|
|
|
+ function padColumns(){
|
|
|
+ var $kb = $('#bodyKb'), $ka = $('#bodyKa');
|
|
|
+ $kb.find('.row-pad').remove();
|
|
|
+ $ka.find('.row-pad').remove();
|
|
|
+ var nKb = $kb.children('.row').length;
|
|
|
+ var nKa = $ka.children('.row').length;
|
|
|
+ var diff = nKb - nKa;
|
|
|
+ var pad = '';
|
|
|
+ if(diff > 0){
|
|
|
+ for(var i=0;i<diff;i++) pad += '<div class="row-pad"></div>';
|
|
|
+ $ka.append(pad);
|
|
|
+ } else if(diff < 0){
|
|
|
+ for(var j=0;j<-diff;j++) pad += '<div class="row-pad"></div>';
|
|
|
+ $kb.append(pad);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function startTimers(p0, p1){
|
|
|
+ if(kbTimer){ clearInterval(kbTimer); kbTimer = null; }
|
|
|
+ if(kaTimer){ clearInterval(kaTimer); kaTimer = null; }
|
|
|
+
|
|
|
+ // 两列页数相同,用一个定时器同步翻页
|
|
|
+ var pageCount = Math.max(kbPages.length, kaPages.length);
|
|
|
+ if(pageCount > 1){
|
|
|
+ kbTimer = setInterval(function(){
|
|
|
+ kbIdx = (kbIdx + 1) % kbPages.length;
|
|
|
+ kaIdx = (kaIdx + 1) % kaPages.length;
|
|
|
+ $('#bodyKb').html(renderPage(kbPages[kbIdx], p0, 'kb'));
|
|
|
+ $('#bodyKa').html(renderPage(kaPages[kaIdx], p1, 'ka'));
|
|
|
+ padColumns();
|
|
|
+ }, PAGE_INTERVAL);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 过滤:保留有任意数据的工序 */
|
|
|
+ function filterGroups(groups, prefix){
|
|
|
+ var filtered = [];
|
|
|
+ groups.forEach(function(g){
|
|
|
+ var rows = (g.rows || []).filter(function(r){
|
|
|
+ var m = (r.prefixMap||{})[prefix];
|
|
|
+ if(!m) return false;
|
|
|
+ return (m.dayOk||0)+(m.dayNg||0)+(m.nightOk||0)+(m.nightNg||0) > 0;
|
|
|
+ });
|
|
|
+ if(rows.length){
|
|
|
+ filtered.push({ title: g.title, rows: rows });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return filtered;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 根据较多列的工序数算出每页行数 */
|
|
|
+ function calcPerPage(totalGroups){
|
|
|
+ if(totalGroups <= 0) return 1;
|
|
|
+ var pageCount;
|
|
|
+ if(totalGroups <= ONE_PAGE_LIMIT){
|
|
|
+ pageCount = 1;
|
|
|
+ } else {
|
|
|
+ pageCount = Math.ceil(totalGroups / MAX_GROUPS_PER_PAGE);
|
|
|
+ }
|
|
|
+ while(pageCount > 1 && Math.ceil(totalGroups / pageCount) < MIN_GROUPS_PER_PAGE){
|
|
|
+ pageCount--;
|
|
|
+ }
|
|
|
+ return Math.ceil(totalGroups / pageCount);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 按固定每页行数切页,页数 = ceil(maxCount/perPage),短列后续页为空 */
|
|
|
+ function paginate(filtered, perPage){
|
|
|
+ var pages = [];
|
|
|
+ if(!filtered.length){ pages.push([]); return pages; }
|
|
|
+ for(var i = 0; i < filtered.length; i += perPage){
|
|
|
+ pages.push(filtered.slice(i, i + perPage));
|
|
|
+ }
|
|
|
+ return pages;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 渲染:每个工序一行,工位号横排,白班/夜班实际+不良,产能合计、不良合计 */
|
|
|
+ function renderPage(pageGroups, prefix, side){
|
|
|
+ if(!pageGroups || !pageGroups.length){
|
|
|
+ return '<div class="empty-tip">暂无数据</div>';
|
|
|
+ }
|
|
|
+ var okCls = (side === 'kb') ? 'num-ok-kb' : 'num-ok-ka';
|
|
|
+ var sh = currentShift();
|
|
|
+ var dayCls = (sh === 'day') ? 'active' : 'inactive';
|
|
|
+ var nightCls = (sh === 'night') ? 'active' : 'inactive';
|
|
|
+ var html = '';
|
|
|
+ pageGroups.forEach(function(g, gi){
|
|
|
+ var rows = g.rows;
|
|
|
+ var dayOk=0, dayNg=0, nightOk=0, nightNg=0;
|
|
|
+ var oprHtml = '';
|
|
|
+ rows.forEach(function(r){
|
|
|
+ var m = (r.prefixMap||{})[prefix] || {};
|
|
|
+ dayOk += (m.dayOk||0);
|
|
|
+ dayNg += (m.dayNg||0);
|
|
|
+ nightOk += (m.nightOk||0);
|
|
|
+ nightNg += (m.nightNg||0);
|
|
|
+ oprHtml += '<span>' + esc(r.oprno||'') + '</span>';
|
|
|
+ });
|
|
|
+ var capTotal = dayOk + nightOk; // 产能合计 = 白班实际 + 夜班实际
|
|
|
+ var ngTotal = dayNg + nightNg; // 不良合计
|
|
|
+ var rowCls = (gi % 2 === 0) ? 'odd' : 'even';
|
|
|
+ if(ngTotal > 0) rowCls += ' warn';
|
|
|
+
|
|
|
+ html += '<div class="row ' + rowCls + '">'
|
|
|
+ + '<div class="cell-name c-name">' + esc(g.title||'') + '</div>'
|
|
|
+ + '<div class="cell-oprno c-oprno">' + oprHtml + '</div>'
|
|
|
+ + '<div class="cell c-num ' + dayCls + '"><span class="cell-num ' + numColor(dayOk, okCls) + '">' + dayOk + '</span></div>'
|
|
|
+ + '<div class="cell c-num ' + dayCls + '"><span class="cell-num ' + numColor(dayNg, 'num-ng') + '">' + dayNg + '</span></div>'
|
|
|
+ + '<div class="cell c-num night ' + nightCls + '"><span class="cell-num ' + numColor(nightOk, okCls) + '">' + nightOk + '</span></div>'
|
|
|
+ + '<div class="cell c-num night ' + nightCls + '"><span class="cell-num ' + numColor(nightNg, 'num-ng') + '">' + nightNg + '</span></div>'
|
|
|
+ + '<div class="cell c-total cell-total">' + capTotal + '</div>'
|
|
|
+ + '<div class="cell c-ngtot cell-ngtot' + (ngTotal>0?'':' zero') + '">' + ngTotal + '</div>'
|
|
|
+ + '</div>';
|
|
|
+ });
|
|
|
+ return html;
|
|
|
+ }
|
|
|
+
|
|
|
+ function numColor(val, cls){
|
|
|
+ return val > 0 ? cls : 'num-zero';
|
|
|
+ }
|
|
|
+
|
|
|
+ function esc(s){
|
|
|
+ return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
|
+ }
|
|
|
+
|
|
|
+ loadPiece();
|
|
|
+ setInterval(loadPiece, 30000);
|
|
|
+ markHeaderShift();
|
|
|
+ setInterval(markHeaderShift, 60000); // 每分钟检查班次切换
|
|
|
|
|
|
+})();
|
|
|
</script>
|
|
|
</body>
|
|
|
-</html>
|
|
|
+</html>
|