liuwei 2 mēneši atpakaļ
vecāks
revīzija
af2bb7ce81
1 mainītis faili ar 94 papildinājumiem un 230 dzēšanām
  1. 94 230
      src/main/resources/views/modules/mes/mesScreen5.html

+ 94 - 230
src/main/resources/views/modules/mes/mesScreen5.html

@@ -99,23 +99,22 @@
 		}
 		.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; }
+		/* ===== 位置:与 screen3 高度规则一致 ===== */
+		.p-alert    { left: 36px;  top: 118px; width: 440px; height: 430px; }
+		.p-quality  { left: 36px;  top: 568px; width: 440px; height: 460px; }
+		.p-product  { display: none; }
 
-		/* 中列: x=480, 宽=960 */
-		.p-table    { left: 480px; top: 130px; width: 960px; height: 575px; }
-		.p-month    { left: 480px; top: 725px; width: 960px; height: 306px; }
+		.p-table    { left: 496px; top: 118px; width: 928px; height: 560px; }
+		.p-month    { display: none; }
 
-		/* 右列: 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-achieve  { display: none; }
+		.p-hourly   { right: 36px; top: 568px; width: 440px; height: 460px; }
 
-		/* 阶段报警信息 - 按模板比例调整 */
-		.p-alert .mes4-ptitle {
+		.p-alert .mes4-ptitle,
+		.p-overview .mes4-ptitle,
+		.p-quality .mes4-ptitle,
+		.p-hourly .mes4-ptitle {
 			height: 40px;
 			line-height: 40px;
 			font-size: 16px;
@@ -123,10 +122,11 @@
 			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; }
+		.p-alert .mes4-pbody { top: 40px; padding: 0 6px 8px; }
+		.p-overview .mes4-pbody { top: 40px; padding: 0; }
+		.p-table .mes4-pbody { top: 8px; padding: 8px 28px 12px; }
+		.p-quality .mes4-pbody,
+		.p-hourly .mes4-pbody { top: 68px; }
 
 		/* ===== 报警信息 ===== */
 		.alert-head {
@@ -195,9 +195,9 @@
 			margin-bottom: 2px;
 			letter-spacing: 1px;
 		}
-		.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; }
+		.op-table td.op-col  { color: #00C8FF; font-weight: bold; font-size: 22px; }
+		.op-table td.op-name { color: #ffffff; text-align: center; font-size: 18px; }
+		.op-table td.op-val  { color: #00F7FF; font-weight: bold; font-size: 22px; }
 
 		/* ===== 产线阶段数据总览 (按模板排布) ===== */
 		.overview-wrap {
@@ -231,18 +231,8 @@
 			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;
+			display: none;
 		}
 		.overview-gauge-wrap canvas { width: 100%; height: 100%; }
 		.overview-gauge-wrap .gauge-txt {
@@ -299,7 +289,7 @@
 
 	<div class="mes4-panel p-alert">
 		<div class="mes4-ptitle">  产线阶段报警信息  </div>
-		<div class="mes4-pbody" style="padding:0">
+		<div class="mes4-pbody">
 			<div class="alert-head"><div>序号</div><div>报警类型</div></div>
 			<div id="alertList"></div>
 		</div>
@@ -311,7 +301,7 @@
 			<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 class="mes4-pbody"><canvas id="chartQuality" class="chart"></canvas></div>
 	</div>
 
 	<div class="mes4-panel p-product">
@@ -320,17 +310,15 @@
 	</div>
 
 	<div class="mes4-panel p-table">
-		<div class="mes4-pbody" style="top:5px;padding:0 20px">
+		<div class="mes4-pbody">
 			<div class="op-table-page-hint" id="opTablePageHint"></div>
 			<table class="op-table">
 				<thead>
 				<tr>
-					<th style="width:110px">工位</th>
-					<th style="width:200px">工位名称</th>
-					<th>计划产能</th>
-					<th>小时产能</th>
+					<th style="width:160px">工位</th>
+					<th style="width:300px">工位名称</th>
 					<th>实际产能</th>
-					<th>当班产能(12小时内)</th>
+					<th>当班产能</th>
 				</tr>
 				</thead>
 				<tbody id="opTableBody"></tbody>
@@ -350,26 +338,19 @@
 				<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 class="oc-value"><span id="productionPeople">48</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 class="oc-value"><span id="deviceCount">56</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 class="oc-value"><span id="planProduction">221</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 class="oc-value"><span id="actualProduction">201</span></div>
 					</div>
 				</div>
 			</div>
@@ -391,7 +372,7 @@
 			<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 class="mes4-pbody"><canvas id="chartHourly" class="chart"></canvas></div>
 	</div>
 </div>
 
@@ -409,7 +390,7 @@
 	function padOpTableRowsToPageSize(html, rowCount) {
 		for (var j = rowCount; j < OP_TABLE_PAGE_SIZE; j++) {
 			var alt = (j % 2 === 1) ? ' op-row-alt' : '';
-			html += '<tr class="op-row-empty' + alt + '"><td colspan="6">&nbsp;</td></tr>';
+			html += '<tr class="op-row-empty' + alt + '"><td colspan="4">&nbsp;</td></tr>';
 		}
 		return html;
 	}
@@ -457,10 +438,14 @@
 		document.getElementById('mes4Time').textContent = pad(h) + ':' + pad(mi) + ':' + pad(s);
 	}
 
-	// ====== 测试数据 ======
+	// ====== 页面数据 ======
 	var mockData = {};
-	/** 每小时上下线:mesProduct/hourlyUpDownOkData(本页 lineSn=XT,上线 OP010 / 下线 OP180) */
-	var HOURLY_API_CFG = { lineSn: 'XT', onlineOprno: 'OP010', offlineOprno: 'OP180' };
+	/** 本屏产线:XT(工位 OP110–OP160) */
+	var LINE_SN = 'XT';
+	var OP_FROM = 110;
+	var OP_TO = 160;
+	/** 每小时上下线:上线 OP110 / 下线 OP160 */
+	var HOURLY_API_CFG = { lineSn: LINE_SN, onlineOprno: 'OP110', offlineOprno: 'OP160' };
 	function buildHourLabels24() {
 		var labels = [];
 		for (var i = 1; i <= 24; i++) {
@@ -505,26 +490,13 @@
 			weekLabels.push((d.getMonth() + 1) + '月' + d.getDate() + '日');
 		}
 
-		// 报警信息由 updateDeviceAlarmAlertsByApi 拉取 mesDeviceAlarm/listData,展示 type
+		// 报警信息由 updateDeviceAlarmAlertsByApi 拉取
 		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 },
-			{ code: 'OP75', name: '下线检测',         plan: 50, hour: 50, real: 50, shift: 50 },
-			{ code: 'OP80', name: '装箱',             plan: 50, hour: 50, real: 50, shift: 50 }
-		];
-
-		// 数据卡
+		// 工位表由 mesLineProcess(XT,OP110–OP160)拉取
+		mockData.opTable = [];
+
+		// 数据卡(总览固定展示)
 		mockData.cards = {
 			productionPeople: 48,
 			deviceCount: 56,
@@ -908,8 +880,6 @@
 			html += '<tr' + ((i % 2 === 1) ? ' class="op-row-alt"' : '') + '>';
 			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>';
@@ -929,41 +899,17 @@
 		}
 	}
 
-	function applyLatestPlanNumsToTable(planNums) {
-		var list = mockData.opTable || [];
-		for (var i = 0; i < list.length; i++) {
-			list[i].plan = planNums;
-		}
-		renderTable();
-	}
+	function applyLatestPlanNumsToTable(planNums) {}
+	function syncAchieveRateWithPlan() {}
 
-	function calcRatePercent(actual, plan) {
-		actual = Number(actual) || 0;
-		plan = Number(plan) || 0;
-		if (plan <= 0) {
-			return 0;
-		}
-		return Math.round(actual * 100 / plan);
+	function parseOprnoNum(code) {
+		var m = String(code || '').toUpperCase().match(/^OP(\d+)/);
+		return m ? parseInt(m[1], 10) : -1;
 	}
 
-	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 isOprnoInRange(code, fromNum, toNum) {
+		var n = parseOprnoNum(code);
+		return n >= fromNum && n <= toNum;
 	}
 
 	function updateLineProcessTableByApi() {
@@ -974,7 +920,7 @@
 			data: {
 				pageNo: 1,
 				pageSize: 5000,
-				lineSn: 'XT'
+				lineSn: LINE_SN
 			},
 			success: function(resp) {
 				var rows = extractUserList(resp);
@@ -982,21 +928,23 @@
 				for (var i = 0; i < rows.length; i++) {
 					var p = rows[i] || {};
 					var ls = String(p.lineSn || p.line_sn || '').toUpperCase();
-					if (ls !== 'XT') continue;
+					if (ls !== LINE_SN) continue;
+					var code = p.oprno || '';
+					if (!isOprnoInRange(code, OP_FROM, OP_TO)) continue;
 					out.push({
-						code: p.oprno || '',
+						code: code,
 						name: p.title || '',
-						plan: (mockData.cards && mockData.cards.planProduction) || 0,
-						hour: 0,
 						real: 0,
-						shift: 0
+						shift: 0,
+						_opNum: parseOprnoNum(code)
 					});
 				}
+				out.sort(function(a, b) { return a._opNum - b._opNum; });
+				mockData.opTable = out;
+				opTablePageIndex = 0;
+				renderTable();
+				startOpTablePageRotate();
 				if (out.length > 0) {
-					mockData.opTable = out;
-					opTablePageIndex = 0;
-					renderTable();
-					startOpTablePageRotate();
 					updateHourlyCapacityByApi();
 				}
 			}
@@ -1005,59 +953,56 @@
 
 	function updateHourlyCapacityByApi() {
 		var list = mockData.opTable || [];
-		if (!list.length) {
-			return;
-		}
+		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;
+			if (list[i] && list[i].code) oprnos.push(list[i].code);
 		}
-		fetchCapacityInto('hourlyCapacityData', 'XT', oprnos, 'hour');
-		fetchCapacityInto('dayCapacityData', 'XT', oprnos, 'real');
-		fetchCapacityInto('shiftCapacityData', 'XT', oprnos, 'shift');
+		if (!oprnos.length) return;
+		fetchCapacityInto('dayCapacityData', LINE_SN, oprnos, 'real', {});
+		fetchCapacityInto('shiftCapacityData', LINE_SN, oprnos, 'shift', { fixedTwoShift: 'true' });
 	}
 
-	// 通用:拉取产能数据并写入表格指定字段(hour=小时产能, real=实际/当天产能, shift=当班产能)
-	function fetchCapacityInto(action, lineSn, oprnos, field) {
+	function fetchCapacityInto(action, lineSn, oprnos, field, extraData) {
+		var data = { lineSn: lineSn, oprnos: oprnos.join(',') };
+		if (extraData) {
+			for (var k in extraData) {
+				if (extraData.hasOwnProperty(k)) data[k] = extraData[k];
+			}
+		}
 		$.ajax({
 			url: '${ctx}/mes/mesProductRecord/' + action,
 			type: 'POST',
 			dataType: 'json',
-			data: {
-				lineSn: lineSn,
-				oprnos: oprnos.join(',')
-			},
+			data: data,
 			success: function(resp) {
-				if (!resp || resp.result !== 'true' || !resp.data) {
-					return;
-				}
+				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;
+					var formatted = code.length === 6 ? code.substring(0, 5) : code;
+					list[i][field] = Number(map[code] != null ? map[code] : map[formatted]) || 0;
 				}
 				renderTable();
 			}
 		});
 	}
 
-	// 近七日产品质检数据分析(产出=半成品入库,不良=返工记录),按产线 XT 统计
+	// 近七日质检:产出=OP160 OK,不良=返工 OP120–OP160
 	function updateWeekQualityByApi() {
 		$.ajax({
 			url: '${ctx}/mes/mesProductRecord/weekQualityData',
 			type: 'POST',
 			dataType: 'json',
-			data: { lineSn: 'XT' },
+			data: {
+				lineSn: LINE_SN,
+				producedOprno: 'OP160',
+				defectOprnoFrom: 'OP120',
+				defectOprnoTo: 'OP160'
+			},
 			success: function(resp) {
-				if (!resp || resp.result !== 'true' || !resp.data) {
-					return;
-				}
+				if (!resp || resp.result !== 'true' || !resp.data) return;
 				var d = resp.data;
 				var produced = d.produced || [];
 				var defect = d.defect || [];
@@ -1072,86 +1017,18 @@
 					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)
+					max: Math.ceil(maxV * 1.15) || 10
 				};
 				drawAllCharts();
 			}
 		});
 	}
 
-	// 各月产量统计图(半成品入库管理按月统计),按产线 XT
-	function updateMonthlyProductByApi() {
-		$.ajax({
-			url: '${ctx}/mes/mesProductRecord/monthlyProductData',
-			type: 'POST',
-			dataType: 'json',
-			data: { lineSn: 'XT' },
-			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 updateMonthlyProductByApi() {}
 
-	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();
-			}
-		});
-	}
-	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 updateLatestPlanProductionByApi() {}
+
+	function renderCards() {}
 
 	function extractUserList(resp) {
 		if (!resp) return [];
@@ -1351,15 +1228,8 @@
 	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() {
@@ -1368,16 +1238,10 @@
 		renderAlerts();
 		renderTable();
 		startOpTablePageRotate();
-		renderCards();
-		updateLatestPlanProductionByApi();
 		updateLineProcessTableByApi();
-		updateProductionPeopleByApi();
-		updateDeviceCountByApi();
-		updateActualProductionByApi();
 		updateDeviceAlarmAlertsByApi();
 		updateHourlyUpDownByApi();
 		updateWeekQualityByApi();
-		updateMonthlyProductByApi();
 		drawAllCharts();
 	}