| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <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>产线阶段统计大屏</title>
- <link rel="stylesheet" href="${ctxStatic}/bootstrap/css/bootstrap.min.css">
- <link rel="stylesheet" href="${ctxStatic}/screen/style.css">
- <style>
- * { margin: 0; padding: 0; box-sizing: border-box; }
- body { overflow: hidden; font-family: "Microsoft YaHei", sans-serif; }
- .mes4-wrapper {
- position: relative;
- width: 1920px;
- height: 1080px;
- background-color: #00091A;
- background-image: url("${ctxStatic}/screen/imgs/ljrSreen1.png");
- background-size: 100% 100%;
- overflow: hidden;
- margin: 0 auto;
- }
- /* ===== 顶部标题栏 ===== */
- .mes4-header {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 90px;
- z-index: 10;
- }
- .mes4-logo {
- position: absolute;
- top: 20px;
- left: 40px;
- height: 50px;
- width: auto;
- }
- .mes4-title {
- position: absolute;
- left: 50%;
- top: 20px;
- transform: translateX(-50%);
- font-size: 38px;
- font-weight: bold;
- color: #FFFFFF;
- letter-spacing: 3px;
- text-shadow: 0 0 10px rgba(77, 201, 245, 0.6);
- white-space: nowrap;
- }
- .mes4-datetime {
- position: absolute;
- top: 32px;
- right: 50px;
- text-align: right;
- }
- .mes4-datetime .mes4-date {
- display: inline-block;
- font-size: 18px;
- color: #FFFFFF;
- line-height: 28px;
- }
- .mes4-datetime .mes4-time {
- display: inline-block;
- margin-left: 14px;
- font-size: 22px;
- color: #FFFFFF;
- font-weight: bold;
- line-height: 28px;
- }
- /* ===== 面板通用 - 使用自定义类名避免与 Bootstrap 的 .panel 冲突 ===== */
- .mes4-panel {
- position: absolute;
- overflow: hidden;
- background: transparent;
- border: none;
- box-shadow: none;
- }
- .mes4-panel .mes4-ptitle {
- height: 42px;
- line-height: 42px;
- text-align: center;
- font-size: 18px;
- font-weight: bold;
- color: #4DC9F5;
- letter-spacing: 1px;
- background: transparent;
- }
- .mes4-panel .mes4-pbody {
- position: absolute;
- top: 42px;
- left: 0;
- right: 0;
- bottom: 0;
- padding: 5px 10px;
- background: transparent;
- }
- .chart { width: 100%; height: 100%; display: block; }
- /* ===== 位置定义 (1920 × 1080 画布) ===== */
- /* 左列: x=30, 宽=430 */
- .p-alert { left: 40px; top: 130px; width: 430px; height: 290px; }
- .p-quality { left: 40px; top: 455px; width: 430px; height: 265px; }
- .p-product { left: 40px; top: 763px; width: 430px; height: 306px; }
- /* 中列: x=480, 宽=960 */
- .p-table { left: 480px; top: 130px; width: 960px; height: 575px; }
- .p-month { left: 480px; top: 725px; width: 960px; height: 306px; }
- /* 右列: right=30, 宽=430 */
- .p-overview { right: 30px; top: 130px; width: 430px; height: 290px; }
- .p-achieve { right: 40px; top: 455px; width: 430px; height: 265px; }
- .p-hourly { right: 40px; top: 763px; width: 430px; height: 306px; }
- /* 阶段报警信息 - 按模板比例调整 */
- .p-alert .mes4-ptitle {
- height: 40px;
- line-height: 40px;
- font-size: 16px;
- color: #4DC9F5;
- font-weight: bold;
- letter-spacing: 1px;
- }
- .p-alert .mes4-pbody { top: 40px; padding: 0; }
- /* 总览标题 */
- .p-overview .mes4-ptitle { height: 40px; line-height: 40px; font-size: 16px; }
- .p-overview .mes4-pbody { top: 40px; }
- /* ===== 报警信息 ===== */
- .alert-head {
- display: flex;
- align-items: center;
- height: 36px;
- padding: 0 22px;
- color: #4DC9F5;
- font-size: 14px;
- font-weight: bold;
- border-bottom: 1px solid rgba(77, 201, 245, 0.3);
- }
- .alert-head > div:nth-child(1) { width: 70px; }
- .alert-head > div:nth-child(2) { flex: 1; }
- .alert-row {
- display: flex;
- align-items: center;
- height: 28px;
- padding: 0 22px;
- color: #ffffff;
- font-size: 13px;
- }
- .alert-row > div:nth-child(1) { width: 70px; color: #4DC9F5; font-weight: bold; }
- .alert-row > div:nth-child(2) { flex: 1; }
- /* ===== OP 表格 ===== */
- .op-table {
- width: 100%;
- border-collapse: collapse;
- color: #ffffff;
- font-size: 16px;
- table-layout: fixed;
- }
- .op-table thead th {
- height: 46px;
- color: #4DC9F5;
- font-weight: normal;
- font-size: 16px;
- background: rgba(0, 100, 180, 0.25);
- border-bottom: 1px solid rgba(77, 201, 245, 0.35);
- text-align: center;
- }
- .op-table tbody td {
- height: 46px;
- text-align: center;
- border-bottom: 1px dashed rgba(77, 201, 245, 0.18);
- }
- .op-table tbody tr:hover td { background: rgba(0, 200, 255, 0.06); }
- .op-table td.op-col { color: #00C8FF; font-weight: bold; font-size: 18px; }
- .op-table td.op-name { color: #ffffff; text-align: center; }
- .op-table td.op-val { color: #00F7FF; font-weight: bold; font-size: 18px; }
- /* ===== 产线阶段数据总览 (按模板排布) ===== */
- .overview-wrap {
- position: relative;
- height: 100%;
- padding: 14px 18px;
- }
- .overview-cards {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 14px 170px;
- height: 100%;
- }
- .overview-card {
- background: transparent;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 4px;
- padding-top: 19px;
- }
- .overview-card .oc-label {
- color: #4DC9F5;
- font-size: 14px;
- margin-bottom: 4px;
- }
- .overview-card .oc-value {
- color: #00F7FF;
- font-size: 24px;
- font-weight: bold;
- line-height: 1;
- }
- .overview-card .oc-value .arrow {
- font-size: 13px;
- color: #00FF88;
- margin-left: 3px;
- }
- .overview-gauge-wrap {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(calc(-50% - 10px), calc(-50% + 16px));
- width: 160px;
- height: 160px;
- }
- .overview-gauge-wrap canvas { width: 100%; height: 100%; }
- .overview-gauge-wrap .gauge-txt {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- text-align: center;
- color: #00F7FF;
- pointer-events: none;
- }
- .overview-gauge-wrap .gauge-txt .val {
- font-size: 30px;
- font-weight: bold;
- line-height: 1;
- }
- .overview-gauge-wrap .gauge-txt .lbl {
- font-size: 13px;
- color: #ffffff;
- margin-top: 6px;
- }
- /* ===== 图例 ===== */
- .legend-inline {
- display: flex;
- align-items: center;
- justify-content: flex-end;
- padding: 4px 18px 0;
- font-size: 13px;
- color: #ffffff;
- gap: 18px;
- }
- .legend-inline .dot {
- display: inline-block;
- width: 12px;
- height: 12px;
- border-radius: 50%;
- margin-right: 5px;
- vertical-align: middle;
- }
- </style>
- </head>
- <body>
- <div class="mes4-wrapper" id="app">
- <div class="mes4-header">
- <img class="mes4-logo" src="${ctxStatic}/screen/imgs/ljrLogo.png" alt="logo">
- <div class="mes4-title">半成品阶段统计大屏</div>
- <div class="mes4-datetime">
- <span class="mes4-date" id="mes4Date"></span>
- <span class="mes4-time" id="mes4Time"></span>
- </div>
- </div>
- <div class="mes4-panel p-alert">
- <div class="mes4-ptitle"> 产线阶段报警信息 </div>
- <div class="mes4-pbody" style="padding:0">
- <div class="alert-head"><div>序号</div><div>报警类型</div></div>
- <div id="alertList"></div>
- </div>
- </div>
- <div class="mes4-panel p-quality">
- <div class="mes4-ptitle"> 近七日产品质检数据分析 </div>
- <div class="legend-inline">
- <span><i class="dot" style="background:#00FF88"></i>产出</span>
- <span><i class="dot" style="background:#00C8FF"></i>不良</span>
- </div>
- <div class="mes4-pbody" style="top:62px"><canvas id="chartQuality" class="chart"></canvas></div>
- </div>
- <div class="mes4-panel p-product">
- <div class="mes4-ptitle"> 近七日产量分析 </div>
- <div class="mes4-pbody"><canvas id="chartProduct" class="chart"></canvas></div>
- </div>
- <div class="mes4-panel p-table">
- <div class="mes4-pbody" style="top:5px;padding:0 20px">
- <table class="op-table">
- <thead>
- <tr>
- <th style="width:110px">工位</th>
- <th style="width:200px">工位名称</th>
- <th>计划产能</th>
- <th>小时产能</th>
- <th>实际产能</th>
- <th>当班产能(12小时内)</th>
- </tr>
- </thead>
- <tbody id="opTableBody"></tbody>
- </table>
- </div>
- </div>
- <div class="mes4-panel p-month">
- <div class="mes4-ptitle">各月产量统计图</div>
- <div class="mes4-pbody"><canvas id="chartMonth" class="chart"></canvas></div>
- </div>
- <div class="mes4-panel p-overview">
- <div class="mes4-ptitle"> 产线阶段数据总览 </div>
- <div class="mes4-pbody" style="padding:0">
- <div class="overview-wrap">
- <div class="overview-cards">
- <div class="overview-card">
- <div class="oc-label">生产人数</div>
- <div class="oc-value"><span id="productionPeople">48</span> <span class="arrow">↑</span></div>
- </div>
- <div class="overview-card">
- <div class="oc-label">设备数量</div>
- <div class="oc-value"><span id="deviceCount">56</span> <span class="arrow">↑</span></div>
- </div>
- <div class="overview-card">
- <div class="oc-label">计划产量</div>
- <div class="oc-value"><span id="planProduction">221</span> <span class="arrow">↑</span></div>
- </div>
- <div class="overview-card">
- <div class="oc-label">实际产量</div>
- <div class="oc-value"><span id="actualProduction">201</span> <span class="arrow">↑</span></div>
- </div>
- </div>
- <div class="overview-gauge-wrap">
- <canvas id="gaugeRate"></canvas>
- <div class="gauge-txt">
- <div class="val"><span id="gaugeVal">70</span>%</div>
- <div class="lbl">今日达成率</div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="mes4-panel p-achieve">
- <div class="mes4-ptitle"> 近七日达成率数据分析 </div>
- <div class="legend-inline">
- <span><i class="dot" style="background:#FFDD00"></i>目标</span>
- <span><i class="dot" style="background:#00C8FF"></i>实际</span>
- </div>
- <div class="mes4-pbody" style="top:62px"><canvas id="chartAchieve" class="chart"></canvas></div>
- </div>
- <div class="mes4-panel p-hourly">
- <div class="mes4-ptitle"> 每小时上下线数据分析 </div>
- <div class="legend-inline">
- <span><i class="dot" style="background:#00FF88"></i>上线</span>
- <span><i class="dot" style="background:#00C8FF"></i>下线</span>
- </div>
- <div class="mes4-pbody" style="top:62px"><canvas id="chartHourly" class="chart"></canvas></div>
- </div>
- </div>
- <script src="${ctxStatic}/jquery-1.11.3.min.js"></script>
- <script>
- (function() {
- function pad(n) { return n < 10 ? '0' + n : '' + n; }
- function updateClock() {
- var now = new Date();
- var y = now.getFullYear();
- var m = now.getMonth() + 1;
- var d = now.getDate();
- var w = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'][now.getDay()];
- document.getElementById('mes4Date').textContent = y + '年' + pad(m) + '月' + pad(d) + '日 ' + w;
- var h = now.getHours(), mi = now.getMinutes(), s = now.getSeconds();
- document.getElementById('mes4Time').textContent = pad(h) + ':' + pad(mi) + ':' + pad(s);
- }
- // ====== 测试数据 ======
- var mockData = {};
- /** 每小时上下线:mesProduct/hourlyUpDownOkData(本页 lineSn=MP,上线 OP120 / 下线 OP190) */
- var HOURLY_API_CFG = { lineSn: 'MP', onlineOprno: 'OP120', offlineOprno: 'OP190' };
- function buildHourLabels24() {
- var hourLabels = [];
- for (var i = 1; i <= 24; i++) {
- hourLabels.push(pad(i));
- }
- return hourLabels;
- }
- function updateHourlyUpDownByApi() {
- $.ajax({
- url: '${ctx}/mes/mesProduct/hourlyUpDownOkData',
- type: 'POST',
- dataType: 'json',
- data: {
- lineSn: HOURLY_API_CFG.lineSn,
- onlineOprno: HOURLY_API_CFG.onlineOprno,
- offlineOprno: HOURLY_API_CFG.offlineOprno
- },
- success: function(resp) {
- if (resp && resp.result === 'true' && resp.data) {
- var d = resp.data;
- if (!d.up || !d.down || d.up.length < 24 || d.down.length < 24) {
- return;
- }
- mockData.hourly = {
- labels: buildHourLabels24(),
- up: d.up,
- down: d.down,
- max: typeof d.max === 'number' ? d.max : 100
- };
- drawAllCharts();
- }
- }
- });
- }
- function generateMockData() {
- // 最近7日日期
- var now = new Date();
- var weekLabels = [];
- for (var i = 6; i >= 0; i--) {
- var d = new Date(now);
- d.setDate(d.getDate() - i);
- weekLabels.push((d.getMonth() + 1) + '月' + d.getDate() + '日');
- }
- // 报警信息由 updateDeviceAlarmAlertsByApi 拉取 mesDeviceAlarm/listData,展示 type
- mockData.alerts = [];
- // OP 表格
- mockData.opTable = [
- { code: 'OP10', name: '上料+打码', plan: 50, hour: 50, real: 50, shift: 50 },
- { code: 'OP20', name: '底板组件-正面FSW', plan: 50, hour: 50, real: 50, shift: 50 },
- { code: 'OP25', name: '底板组件-打磨', plan: 50, hour: 50, real: 50, shift: 50 },
- { code: 'OP30', name: '底板组件-反面FSW', plan: 50, hour: 50, real: 50, shift: 50 },
- { code: 'OP40', name: '底板组件-CNC', plan: 50, hour: 50, real: 50, shift: 50 },
- { code: 'OP50', name: '干冰清洁', plan: 50, hour: 50, real: 50, shift: 50 },
- { code: 'OP55', name: '模组梁+封板预装', plan: 50, hour: 50, real: 50, shift: 50 },
- { code: 'OP60', name: '封板正面FSW', plan: 50, hour: 50, real: 50, shift: 50 },
- { code: 'OP65', name: '打磨', plan: 50, hour: 50, real: 50, shift: 50 },
- { code: 'OP70', name: '封板反面FSW', plan: 50, hour: 50, real: 50, shift: 50 }
- ];
- // 数据卡
- mockData.cards = {
- productionPeople: 48,
- deviceCount: 56,
- planProduction: 221,
- actualProduction: 201
- };
- mockData.rate = 70;
- // 近七日产品质检
- mockData.qualityInspect = {
- labels: weekLabels,
- produced: [400, 321, 354, 164, 241, 342, 231],
- defect: [345, 256, 312, 123, 214, 286, 189],
- max: 500
- };
- // 近七日达成率
- mockData.achieveRate = {
- labels: weekLabels,
- target: [1150, 1160, 1180, 1165, 1180, 1180, 1170],
- actual: [1150, 1160, 1180, 1165, 1200, 1200, 1170],
- max: 1300, min: 1100
- };
- // 近七日产量
- mockData.productTrend = {
- labels: weekLabels,
- data: [1100, 1100, 1200, 1125, 1125, 1180, 1150],
- max: 1300, min: 1000
- };
- // 每小时上下线 (24 小时)
- var hourLabels = [], up = [], down = [];
- for (var i = 1; i <= 24; i++) {
- hourLabels.push(pad(i));
- up.push(Math.round(60 + Math.random() * 30));
- down.push(Math.round(50 + Math.random() * 30));
- }
- mockData.hourly = { labels: hourLabels, up: up, down: down, max: 100 };
- // 各月产量
- mockData.monthly = {
- labels: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'],
- data: [ 350, 340, 480, 360, 350, 360, 420, 410, 380, 420, 470, 400 ],
- max: 500
- };
- }
- // ====== 工具函数 ======
- function hexToRgba(hex, a) {
- var r = parseInt(hex.slice(1, 3), 16),
- g = parseInt(hex.slice(3, 5), 16),
- b = parseInt(hex.slice(5, 7), 16);
- return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
- }
- function prepareCanvas(id) {
- var c = document.getElementById(id);
- if (!c) return null;
- var p = c.parentElement;
- var w = p.clientWidth, h = p.clientHeight;
- if (c.width !== w || c.height !== h) { c.width = w; c.height = h; }
- return { ctx: c.getContext('2d'), w: w, h: h };
- }
- function drawYAxis(ctx, padL, padT, cw, ch, maxV, minV) {
- minV = minV || 0;
- ctx.fillStyle = 'rgba(77,201,245,0.8)';
- ctx.font = '11px Microsoft YaHei';
- ctx.textAlign = 'right';
- ctx.strokeStyle = 'rgba(0,143,253,0.18)';
- ctx.lineWidth = 1;
- for (var i = 0; i <= 4; i++) {
- var val = Math.round(minV + (maxV - minV) * (4 - i) / 4);
- var y = padT + ch * i / 4;
- ctx.fillText(val, padL - 5, y + 4);
- ctx.beginPath();
- ctx.moveTo(padL, y);
- ctx.lineTo(padL + cw, y);
- ctx.stroke();
- }
- }
- // 双柱状图 - 近七日产品质检 (产出/不良)
- function drawDoubleBar(id, a, b, labels, maxV) {
- var p = prepareCanvas(id); if (!p) return;
- var ctx = p.ctx, w = p.w, h = p.h;
- var padL = 38, padR = 10, padT = 12, padB = 22;
- var cw = w - padL - padR, ch = h - padT - padB;
- ctx.clearRect(0, 0, w, h);
- drawYAxis(ctx, padL, padT, cw, ch, maxV);
- if (!a || a.length < 1) return;
- var gw = cw / a.length, bw = gw * 0.3;
- for (var i = 0; i < a.length; i++) {
- var cx = padL + i * gw + gw / 2;
- var h1 = (a[i] / maxV) * ch;
- var g1 = ctx.createLinearGradient(0, padT + ch - h1, 0, padT + ch);
- g1.addColorStop(0, '#00FF88'); g1.addColorStop(1, 'rgba(0,255,136,0.15)');
- ctx.fillStyle = g1;
- ctx.fillRect(cx - bw - 2, padT + ch - h1, bw, h1);
- var h2 = (b[i] / maxV) * ch;
- var g2 = ctx.createLinearGradient(0, padT + ch - h2, 0, padT + ch);
- g2.addColorStop(0, '#00C8FF'); g2.addColorStop(1, 'rgba(0,200,255,0.15)');
- ctx.fillStyle = g2;
- ctx.fillRect(cx + 2, padT + ch - h2, bw, h2);
- ctx.fillStyle = '#00FF88'; ctx.font = 'bold 10px Microsoft YaHei';
- ctx.textAlign = 'center'; ctx.fillText(a[i], cx - bw / 2 - 2, padT + ch - h1 - 4);
- ctx.fillStyle = '#00C8FF'; ctx.fillText(b[i], cx + bw / 2 + 2, padT + ch - h2 - 4);
- ctx.fillStyle = 'rgba(77,201,245,0.9)'; ctx.font = '11px Microsoft YaHei';
- ctx.fillText(labels[i], cx, h - 6);
- }
- }
- // 单折线图 (近七日产量, 平滑+面积)
- function drawLineChart(id, data, labels, maxV, minV, color) {
- var p = prepareCanvas(id); if (!p) return;
- var ctx = p.ctx, w = p.w, h = p.h;
- var padL = 45, padR = 12, padT = 15, padB = 25;
- var cw = w - padL - padR, ch = h - padT - padB;
- color = color || '#00C8FF';
- minV = minV || 0;
- ctx.clearRect(0, 0, w, h);
- drawYAxis(ctx, padL, padT, cw, ch, maxV, minV);
- if (!data || data.length < 2) return;
- var stepX = cw / (data.length - 1);
- var range = maxV - minV;
- var grad = ctx.createLinearGradient(0, padT, 0, padT + ch);
- grad.addColorStop(0, hexToRgba(color, 0.4));
- grad.addColorStop(1, hexToRgba(color, 0.02));
- ctx.beginPath();
- ctx.moveTo(padL, padT + ch);
- for (var i = 0; i < data.length; i++) {
- var x = padL + i * stepX;
- var y = padT + ch - ((data[i] - minV) / range) * ch;
- if (i === 0) ctx.lineTo(x, y);
- else {
- var px = padL + (i - 1) * stepX;
- var py = padT + ch - ((data[i - 1] - minV) / range) * ch;
- var cpx = (px + x) / 2;
- ctx.bezierCurveTo(cpx, py, cpx, y, x, y);
- }
- }
- ctx.lineTo(padL + (data.length - 1) * stepX, padT + ch);
- ctx.closePath();
- ctx.fillStyle = grad;
- ctx.fill();
- ctx.beginPath();
- for (var j = 0; j < data.length; j++) {
- var x2 = padL + j * stepX;
- var y2 = padT + ch - ((data[j] - minV) / range) * ch;
- if (j === 0) ctx.moveTo(x2, y2);
- else {
- var px2 = padL + (j - 1) * stepX;
- var py2 = padT + ch - ((data[j - 1] - minV) / range) * ch;
- var cpx2 = (px2 + x2) / 2;
- ctx.bezierCurveTo(cpx2, py2, cpx2, y2, x2, y2);
- }
- }
- ctx.strokeStyle = color; ctx.lineWidth = 2; ctx.stroke();
- ctx.font = 'bold 11px Microsoft YaHei'; ctx.textAlign = 'center';
- for (var k = 0; k < data.length; k++) {
- var x3 = padL + k * stepX;
- var y3 = padT + ch - ((data[k] - minV) / range) * ch;
- ctx.beginPath(); ctx.arc(x3, y3, 3, 0, Math.PI * 2);
- ctx.fillStyle = color; ctx.fill();
- ctx.strokeStyle = '#fff'; ctx.lineWidth = 1.5; ctx.stroke();
- ctx.fillStyle = '#ffffff';
- ctx.fillText(data[k], x3, y3 - 8);
- }
- ctx.fillStyle = 'rgba(77,201,245,0.9)'; ctx.font = '11px Microsoft YaHei';
- for (var m = 0; m < labels.length; m++) {
- var xx = padL + m * stepX;
- ctx.fillText(labels[m], xx, h - 6);
- }
- }
- // 双折线图 (目标/实际)
- function drawDualLine(id, a, b, labels, maxV, minV) {
- var p = prepareCanvas(id); if (!p) return;
- var ctx = p.ctx, w = p.w, h = p.h;
- var padL = 45, padR = 12, padT = 12, padB = 22;
- var cw = w - padL - padR, ch = h - padT - padB;
- minV = minV || 0;
- var range = maxV - minV;
- ctx.clearRect(0, 0, w, h);
- drawYAxis(ctx, padL, padT, cw, ch, maxV, minV);
- if (!a || a.length < 2) return;
- var stepX = cw / (a.length - 1);
- function draw(arr, color) {
- var grad = ctx.createLinearGradient(0, padT, 0, padT + ch);
- grad.addColorStop(0, hexToRgba(color, 0.3));
- grad.addColorStop(1, hexToRgba(color, 0.02));
- ctx.beginPath(); ctx.moveTo(padL, padT + ch);
- for (var i = 0; i < arr.length; i++) {
- var x = padL + i * stepX;
- var y = padT + ch - ((arr[i] - minV) / range) * ch;
- if (i === 0) ctx.lineTo(x, y);
- else {
- var px = padL + (i - 1) * stepX;
- var py = padT + ch - ((arr[i - 1] - minV) / range) * ch;
- var cpx = (px + x) / 2;
- ctx.bezierCurveTo(cpx, py, cpx, y, x, y);
- }
- }
- ctx.lineTo(padL + (arr.length - 1) * stepX, padT + ch);
- ctx.closePath(); ctx.fillStyle = grad; ctx.fill();
- ctx.beginPath();
- for (var j = 0; j < arr.length; j++) {
- var x2 = padL + j * stepX;
- var y2 = padT + ch - ((arr[j] - minV) / range) * ch;
- if (j === 0) ctx.moveTo(x2, y2);
- else {
- var px2 = padL + (j - 1) * stepX;
- var py2 = padT + ch - ((arr[j - 1] - minV) / range) * ch;
- var cpx2 = (px2 + x2) / 2;
- ctx.bezierCurveTo(cpx2, py2, cpx2, y2, x2, y2);
- }
- }
- ctx.strokeStyle = color; ctx.lineWidth = 2; ctx.stroke();
- for (var k = 0; k < arr.length; k++) {
- var x3 = padL + k * stepX;
- var y3 = padT + ch - ((arr[k] - minV) / range) * ch;
- ctx.beginPath(); ctx.arc(x3, y3, 3, 0, Math.PI * 2);
- ctx.fillStyle = color; ctx.fill();
- }
- }
- draw(a, '#FFDD00');
- draw(b, '#00C8FF');
- ctx.fillStyle = '#ffffff'; ctx.font = '10px Microsoft YaHei'; ctx.textAlign = 'center';
- for (var i = 0; i < b.length; i++) {
- var x = padL + i * stepX;
- var y = padT + ch - ((b[i] - minV) / range) * ch;
- ctx.fillText(b[i], x, y - 6);
- }
- ctx.fillStyle = 'rgba(77,201,245,0.9)';
- for (var i2 = 0; i2 < labels.length; i2++) {
- var x2 = padL + i2 * stepX;
- ctx.fillText(labels[i2], x2, h - 6);
- }
- }
- // 双面积折线图 (每小时上下线)
- function drawAreaLine(id, up, down, labels, maxV) {
- var p = prepareCanvas(id); if (!p) return;
- var ctx = p.ctx, w = p.w, h = p.h;
- var padL = 30, padR = 12, padT = 12, padB = 22;
- var cw = w - padL - padR, ch = h - padT - padB;
- ctx.clearRect(0, 0, w, h);
- drawYAxis(ctx, padL, padT, cw, ch, maxV);
- if (!up || up.length < 2) return;
- var stepX = cw / (up.length - 1);
- function draw(arr, color) {
- var grad = ctx.createLinearGradient(0, padT, 0, padT + ch);
- grad.addColorStop(0, hexToRgba(color, 0.45));
- grad.addColorStop(1, hexToRgba(color, 0.05));
- ctx.beginPath(); ctx.moveTo(padL, padT + ch);
- for (var i = 0; i < arr.length; i++) {
- var x = padL + i * stepX;
- var y = padT + ch - (arr[i] / maxV) * ch;
- if (i === 0) ctx.lineTo(x, y);
- else {
- var px = padL + (i - 1) * stepX;
- var py = padT + ch - (arr[i - 1] / maxV) * ch;
- var cpx = (px + x) / 2;
- ctx.bezierCurveTo(cpx, py, cpx, y, x, y);
- }
- }
- ctx.lineTo(padL + (arr.length - 1) * stepX, padT + ch);
- ctx.closePath(); ctx.fillStyle = grad; ctx.fill();
- ctx.beginPath();
- for (var j = 0; j < arr.length; j++) {
- var x2 = padL + j * stepX;
- var y2 = padT + ch - (arr[j] / maxV) * ch;
- if (j === 0) ctx.moveTo(x2, y2);
- else {
- var px2 = padL + (j - 1) * stepX;
- var py2 = padT + ch - (arr[j - 1] / maxV) * ch;
- var cpx2 = (px2 + x2) / 2;
- ctx.bezierCurveTo(cpx2, py2, cpx2, y2, x2, y2);
- }
- }
- ctx.strokeStyle = color; ctx.lineWidth = 1.6; ctx.stroke();
- }
- draw(up, '#00FF88');
- draw(down, '#00C8FF');
- ctx.fillStyle = 'rgba(77,201,245,0.9)'; ctx.font = '10px Microsoft YaHei'; ctx.textAlign = 'center';
- for (var i = 0; i < labels.length; i++) {
- if (i % 2 === 0) {
- var x = padL + i * stepX;
- ctx.fillText(labels[i], x, h - 6);
- }
- }
- }
- // 月产量柱状图 (渐变条)
- function drawMonthBar(id, data, labels, maxV) {
- var p = prepareCanvas(id); if (!p) return;
- var ctx = p.ctx, w = p.w, h = p.h;
- var padL = 42, padR = 12, padT = 15, padB = 25;
- var cw = w - padL - padR, ch = h - padT - padB;
- ctx.clearRect(0, 0, w, h);
- drawYAxis(ctx, padL, padT, cw, ch, maxV);
- if (!data || data.length < 1) return;
- var gw = cw / data.length, bw = gw * 0.35;
- for (var i = 0; i < data.length; i++) {
- var cx = padL + i * gw + gw / 2;
- var bh = (data[i] / maxV) * ch;
- var grad = ctx.createLinearGradient(0, padT + ch - bh, 0, padT + ch);
- grad.addColorStop(0, '#00FF88');
- grad.addColorStop(1, 'rgba(0,200,255,0.15)');
- ctx.fillStyle = grad;
- ctx.fillRect(cx - bw / 2, padT + ch - bh, bw, bh);
- ctx.fillStyle = 'rgba(77,201,245,0.9)';
- ctx.font = '11px Microsoft YaHei';
- ctx.textAlign = 'center';
- ctx.fillText(labels[i], cx, h - 6);
- }
- }
- // 半环形仪表盘 (今日达成率)
- function drawGauge(id, percent) {
- var p = prepareCanvas(id); if (!p) return;
- var ctx = p.ctx, w = p.w, h = p.h;
- ctx.clearRect(0, 0, w, h);
- var cx = w / 2, cy = h / 2;
- var r = Math.min(w, h) / 2 - 8;
- // 底环
- ctx.beginPath();
- ctx.arc(cx, cy, r, 0, Math.PI * 2);
- ctx.lineWidth = 10;
- ctx.strokeStyle = 'rgba(0,143,253,0.25)';
- ctx.stroke();
- // 进度环
- var start = -Math.PI / 2;
- var end = start + Math.PI * 2 * (percent / 100);
- var grad = ctx.createLinearGradient(0, 0, w, h);
- grad.addColorStop(0, '#00C8FF');
- grad.addColorStop(1, '#00FF88');
- ctx.beginPath();
- ctx.arc(cx, cy, r, start, end, false);
- ctx.lineWidth = 10;
- ctx.strokeStyle = grad;
- ctx.lineCap = 'round';
- ctx.stroke();
- // 外环刻度
- ctx.beginPath();
- ctx.arc(cx, cy, r + 10, 0, Math.PI * 2);
- ctx.lineWidth = 1;
- ctx.strokeStyle = 'rgba(0,200,255,0.35)';
- ctx.stroke();
- }
- function escapeHtml(s) {
- if (s == null || s === '') return '';
- return String(s)
- .replace(/&/g, '&')
- .replace(/</g, '<')
- .replace(/>/g, '>')
- .replace(/"/g, '"');
- }
- // ====== 渲染列表(text 为设备报警记录的 type 字段)======
- function renderAlerts() {
- var html = '';
- var list = mockData.alerts || [];
- for (var i = 0; i < list.length; i++) {
- html += '<div class="alert-row"><div>' + list[i].no + '</div><div>' + escapeHtml(list[i].text) + '</div></div>';
- }
- var el = document.getElementById('alertList');
- if (el) el.innerHTML = html;
- }
- function renderTable() {
- var html = '';
- var list = mockData.opTable || [];
- for (var i = 0; i < list.length; i++) {
- var r = list[i];
- html += '<tr>';
- html += '<td class="op-col">' + r.code + '</td>';
- html += '<td class="op-name">' + r.name + '</td>';
- html += '<td class="op-val">' + r.plan + '</td>';
- html += '<td class="op-val">' + r.hour + '</td>';
- html += '<td class="op-val">' + r.real + '</td>';
- html += '<td class="op-val">' + r.shift + '</td>';
- html += '</tr>';
- }
- var el = document.getElementById('opTableBody');
- if (el) el.innerHTML = html;
- }
- function applyLatestPlanNumsToTable(planNums) {
- var list = mockData.opTable || [];
- for (var i = 0; i < list.length; i++) {
- list[i].plan = planNums;
- }
- renderTable();
- }
- function calcRatePercent(actual, plan) {
- actual = Number(actual) || 0;
- plan = Number(plan) || 0;
- if (plan <= 0) {
- return 0;
- }
- return Math.round(actual * 100 / plan);
- }
- function syncAchieveRateWithPlan() {
- mockData.cards = mockData.cards || {};
- mockData.achieveRate = mockData.achieveRate || { labels: [], actual: [] };
- var planNums = Number(mockData.cards.planProduction) || 0;
- var actualProduction = Number(mockData.cards.actualProduction) || 0;
- var labels = mockData.achieveRate.labels || [];
- var actualSeries = mockData.achieveRate.actual || [];
- var targetSeries = [];
- for (var i = 0; i < labels.length; i++) {
- targetSeries.push(planNums);
- }
- var maxVal = Math.max.apply(null, targetSeries.concat(actualSeries).concat([10]));
- mockData.achieveRate.target = targetSeries;
- mockData.achieveRate.max = maxVal <= 0 ? 10 : Math.ceil(maxVal * 1.1);
- mockData.achieveRate.min = 0;
- mockData.rate = calcRatePercent(actualProduction, planNums);
- renderCards();
- drawAllCharts();
- }
- function updateLineProcessTableByApi() {
- $.ajax({
- url: '${ctx}/mes/mesLineProcess/listData',
- type: 'POST',
- dataType: 'json',
- data: {
- pageNo: 1,
- pageSize: 5000,
- lineSn: 'MP'
- },
- success: function(resp) {
- var rows = extractUserList(resp);
- var out = [];
- for (var i = 0; i < rows.length; i++) {
- var p = rows[i] || {};
- var ls = String(p.lineSn || p.line_sn || '').toUpperCase();
- if (ls !== 'MP') continue;
- out.push({
- code: p.oprno || '',
- name: p.title || '',
- plan: (mockData.cards && mockData.cards.planProduction) || 0,
- hour: 0,
- real: 0,
- shift: 0
- });
- }
- if (out.length > 0) {
- mockData.opTable = out;
- renderTable();
- updateHourlyCapacityByApi();
- }
- }
- });
- }
- function updateHourlyCapacityByApi() {
- var list = mockData.opTable || [];
- if (!list.length) {
- return;
- }
- var oprnos = [];
- for (var i = 0; i < list.length; i++) {
- if (list[i] && list[i].code) {
- oprnos.push(list[i].code);
- }
- }
- if (!oprnos.length) {
- return;
- }
- fetchCapacityInto('hourlyCapacityData', 'MP', oprnos, 'hour');
- fetchCapacityInto('dayCapacityData', 'MP', oprnos, 'real');
- fetchCapacityInto('shiftCapacityData', 'MP', oprnos, 'shift');
- }
- // 通用:拉取产能数据并写入表格指定字段(hour=小时产能, real=实际/当天产能, shift=当班产能)
- function fetchCapacityInto(action, lineSn, oprnos, field) {
- $.ajax({
- url: '${ctx}/mes/mesProductRecord/' + action,
- type: 'POST',
- dataType: 'json',
- data: {
- lineSn: lineSn,
- oprnos: oprnos.join(',')
- },
- success: function(resp) {
- if (!resp || resp.result !== 'true' || !resp.data) {
- return;
- }
- var map = resp.data || {};
- var list = mockData.opTable || [];
- for (var i = 0; i < list.length; i++) {
- var code = list[i].code || '';
- list[i][field] = Number(map[code]) || 0;
- }
- renderTable();
- }
- });
- }
- function updateLatestPlanProductionByApi() {
- $.ajax({
- url: '${ctx}/mes/mesPlan/latestPlanNums',
- type: 'POST',
- dataType: 'json',
- success: function(resp) {
- if (!resp || resp.result !== 'true' || !resp.data) {
- return;
- }
- var planNums = Number(resp.data.nums) || 0;
- mockData.cards = mockData.cards || {};
- mockData.cards.planProduction = planNums;
- applyLatestPlanNumsToTable(planNums);
- syncAchieveRateWithPlan();
- }
- });
- }
- // 近七日产品质检数据分析(产出=半成品入库,不良=返工记录),按产线 MP 统计
- function updateWeekQualityByApi() {
- $.ajax({
- url: '${ctx}/mes/mesProductRecord/weekQualityData',
- type: 'POST',
- dataType: 'json',
- data: { lineSn: 'MP' },
- success: function(resp) {
- if (!resp || resp.result !== 'true' || !resp.data) {
- return;
- }
- var d = resp.data;
- var produced = d.produced || [];
- var defect = d.defect || [];
- var maxV = 10;
- for (var i = 0; i < produced.length; i++) {
- if (Number(produced[i]) > maxV) maxV = Number(produced[i]);
- }
- for (var j = 0; j < defect.length; j++) {
- if (Number(defect[j]) > maxV) maxV = Number(defect[j]);
- }
- mockData.qualityInspect = {
- labels: d.labels || [],
- produced: produced,
- defect: defect,
- max: Math.ceil(maxV * 1.2)
- };
- // 近七日产量分析(折线图):产量取每日入库数量(半成品入库管理)
- var pMax = 0, pMin = Number.MAX_VALUE;
- for (var k = 0; k < produced.length; k++) {
- var v = Number(produced[k]) || 0;
- if (v > pMax) pMax = v;
- if (v < pMin) pMin = v;
- }
- if (pMin === Number.MAX_VALUE) { pMin = 0; }
- var pad = Math.max(1, Math.round((pMax - pMin) * 0.2));
- mockData.productTrend = {
- labels: d.labels || [],
- data: produced,
- max: pMax + pad,
- min: Math.max(0, pMin - pad)
- };
- drawAllCharts();
- }
- });
- }
- // 各月产量统计图(半成品入库管理按月统计),按产线 MP
- function updateMonthlyProductByApi() {
- $.ajax({
- url: '${ctx}/mes/mesProductRecord/monthlyProductData',
- type: 'POST',
- dataType: 'json',
- data: { lineSn: 'MP' },
- success: function(resp) {
- if (!resp || resp.result !== 'true' || !resp.data) {
- return;
- }
- var d = resp.data;
- var data = d.data || [];
- var maxV = 10;
- for (var i = 0; i < data.length; i++) {
- if (Number(data[i]) > maxV) maxV = Number(data[i]);
- }
- mockData.monthly = {
- labels: d.labels || [],
- data: data,
- max: Math.ceil(maxV * 1.2)
- };
- drawAllCharts();
- }
- });
- }
- function renderCards() {
- var c = mockData.cards || {};
- var m = {
- productionPeople: c.productionPeople,
- deviceCount: c.deviceCount,
- planProduction: c.planProduction,
- actualProduction: c.actualProduction,
- gaugeVal: mockData.rate
- };
- for (var k in m) {
- var el = document.getElementById(k);
- if (el && m[k] != null) el.textContent = m[k];
- }
- }
- function extractUserList(resp) {
- if (!resp) return [];
- if (Object.prototype.toString.call(resp.list) === '[object Array]') return resp.list;
- if (Object.prototype.toString.call(resp.rows) === '[object Array]') return resp.rows;
- if (resp.data) {
- if (Object.prototype.toString.call(resp.data.list) === '[object Array]') return resp.data.list;
- if (Object.prototype.toString.call(resp.data.rows) === '[object Array]') return resp.data.rows;
- }
- return [];
- }
- function updateDeviceAlarmAlertsByApi() {
- $.ajax({
- url: '${ctx}/mes/mesDeviceAlarm/listData',
- type: 'POST',
- dataType: 'json',
- data: {
- pageNo: 1,
- pageSize: 50,
- state: '0' // 只显示待处理的报警
- },
- success: function(resp) {
- var rows = extractUserList(resp);
- var alerts = [];
- for (var i = 0; i < rows.length; i++) {
- var r = rows[i] || {};
- if (String(r.state) !== '0') continue; // 双保险:跳过非待处理
- var typ = (r.type != null && r.type !== undefined) ? String(r.type) : '';
- alerts.push({ no: alerts.length + 1, text: typ });
- }
- mockData.alerts = alerts;
- renderAlerts();
- },
- error: function() {
- mockData.alerts = [];
- renderAlerts();
- }
- });
- }
- function updateProductionPeopleByApi() {
- $.ajax({
- url: '${ctx}/sys/empUser/listData',
- type: 'POST',
- dataType: 'json',
- data: {
- pageNo: 1,
- pageSize: 5000,
- 'employee.office.officeName': '生产部'
- },
- success: function(resp) {
- var peopleCount = 0;
- var users = extractUserList(resp);
- for (var i = 0; i < users.length; i++) {
- var u = users[i] || {};
- var office = (u.employee && u.employee.office) ? u.employee.office : {};
- var officeName = office.officeName || '';
- var normalizedOfficeName = (officeName + '').replace(/\s/g, '');
- if (
- normalizedOfficeName === '生产部' ||
- /[/\\>]+生产部$/.test(normalizedOfficeName)
- ) {
- peopleCount++;
- }
- }
- mockData.cards = mockData.cards || {};
- mockData.cards.productionPeople = peopleCount;
- var target = document.getElementById('productionPeople');
- if (target) target.textContent = peopleCount;
- }
- });
- }
- function updateDeviceCountByApi() {
- $.ajax({
- url: '${ctx}/mes/mesDevice/listData',
- type: 'POST',
- dataType: 'json',
- data: {
- pageNo: 1,
- pageSize: 1
- },
- success: function(resp) {
- var deviceCount = 0;
- if (resp && typeof resp.count === 'number') {
- deviceCount = resp.count;
- } else {
- var devices = extractUserList(resp);
- deviceCount = devices.length;
- }
- mockData.cards = mockData.cards || {};
- mockData.cards.deviceCount = deviceCount;
- var target = document.getElementById('deviceCount');
- if (target) target.textContent = deviceCount;
- }
- });
- }
- function isOpr190Family(oprno) {
- var op = (oprno || '').replace(/\s/g, '').toUpperCase();
- if (op.length < 5 || op.indexOf('OP190') !== 0) {
- return false;
- }
- if (op.length === 5) {
- return op === 'OP190';
- }
- return /^OP190[A-Z0-9_-]+$/.test(op);
- }
- function isRecordContentOk(content) {
- var c = (content || '').replace(/\s/g, '').toUpperCase();
- return c === 'OK';
- }
- function applyActualProductionCount(n) {
- mockData.cards = mockData.cards || {};
- mockData.cards.actualProduction = n;
- syncAchieveRateWithPlan();
- }
- function getCalendarDayUpdateDateRange() {
- var now = new Date();
- var pad = function(n) { return n < 10 ? '0' + n : '' + n; };
- var dateStr = now.getFullYear() + '-' + pad(now.getMonth() + 1) + '-' + pad(now.getDate());
- return {
- gte: dateStr + ' 00:00:00',
- lte: dateStr + ' 23:59:59',
- startMs: new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime(),
- endMs: new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999).getTime()
- };
- }
- function parseRecordDateMs(val) {
- if (val == null || val === '') {
- return NaN;
- }
- if (typeof val === 'number' && !isNaN(val)) {
- return val;
- }
- var s = String(val).trim().replace(/-/g, '/');
- var t = Date.parse(s);
- return isNaN(t) ? NaN : t;
- }
- function isRecordWithinToday(r, day) {
- var t = parseRecordDateMs(r.updateDate || r.update_date);
- if (isNaN(t)) {
- return false;
- }
- return t >= day.startMs && t <= day.endMs;
- }
- function updateActualProductionByApi() {
- var dayRange = getCalendarDayUpdateDateRange();
- var pageSize = 3000;
- var maxPages = 200;
- var pageNo = 1;
- var totalOk = 0;
- function fetchPage() {
- $.ajax({
- url: '${ctx}/mes/mesProductRecord/listData',
- type: 'POST',
- dataType: 'json',
- data: {
- pageNo: pageNo,
- pageSize: pageSize,
- oprno: 'OP190',
- content: 'OK',
- lineSn: 'MP',
- updateDate_gte: dayRange.gte,
- updateDate_lte: dayRange.lte
- },
- success: function(resp) {
- var list = extractUserList(resp);
- for (var i = 0; i < list.length; i++) {
- var r = list[i] || {};
- if (isOpr190Family(r.oprno) && isRecordContentOk(r.content) && isRecordWithinToday(r, dayRange) && String(r.lineSn || r.line_sn || '').toUpperCase() === 'MP') {
- totalOk++;
- }
- }
- if (list.length === pageSize && pageNo < maxPages) {
- pageNo++;
- fetchPage();
- } else {
- applyActualProductionCount(totalOk);
- }
- },
- error: function() {
- applyActualProductionCount(totalOk);
- }
- });
- }
- fetchPage();
- }
- function drawAllCharts() {
- var q = mockData.qualityInspect;
- if (q) drawDoubleBar('chartQuality', q.produced, q.defect, q.labels, q.max);
- var t = mockData.productTrend;
- if (t) drawLineChart('chartProduct', t.data, t.labels, t.max, t.min, '#00C8FF');
- var a = mockData.achieveRate;
- if (a) drawDualLine('chartAchieve', a.target, a.actual, a.labels, a.max, a.min);
- var hr = mockData.hourly;
- if (hr) drawAreaLine('chartHourly', hr.up, hr.down, hr.labels, hr.max);
- var mo = mockData.monthly;
- if (mo) drawMonthBar('chartMonth', mo.data, mo.labels, mo.max);
- drawGauge('gaugeRate', mockData.rate || 0);
- }
- function refreshData() {
- generateMockData();
- renderAlerts();
- renderTable();
- renderCards();
- updateLatestPlanProductionByApi();
- updateLineProcessTableByApi();
- updateProductionPeopleByApi();
- updateDeviceCountByApi();
- updateActualProductionByApi();
- updateDeviceAlarmAlertsByApi();
- updateHourlyUpDownByApi();
- updateWeekQualityByApi();
- updateMonthlyProductByApi();
- drawAllCharts();
- }
- function changeZoom() {
- var wb = $(window).width() / 1920;
- var hb = $(window).height() / 1080;
- $('body').css({ 'zoom': wb >= hb ? hb : wb });
- }
- $(window).resize(function() {
- changeZoom();
- drawAllCharts();
- });
- $(function() {
- changeZoom();
- updateClock();
- setInterval(updateClock, 1000);
- refreshData();
- // 定期刷新数据 (2 分钟)
- setInterval(refreshData, 1000 * 60 * 2);
- // 每秒重绘 (应对 zoom / resize)
- setInterval(drawAllCharts, 1000);
- });
- })();
- </script>
- </body>
- </html>
|