zhanghe hace 4 meses
padre
commit
743f22a78a

+ 11 - 0
src/main/java/com/jeesite/modules/mes/dao/MesQualityDao.java

@@ -3,6 +3,10 @@ package com.jeesite.modules.mes.dao;
 import com.jeesite.common.dao.CrudDao;
 import com.jeesite.common.mybatis.annotation.MyBatisDao;
 import com.jeesite.modules.mes.entity.MesQuality;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
 
 /**
  * 抽检记录DAO接口
@@ -13,4 +17,11 @@ import com.jeesite.modules.mes.entity.MesQuality;
 public interface MesQualityDao extends CrudDao<MesQuality> {
     MesQuality findInfo(MesQuality mesQuality);
 
+    /**
+     * 按天 + 检查结果(OK/NG) 分组统计抽检数量(指定时间段)
+     * 返回 [{day: 'yyyy-MM-dd', result: 'OK'/'NG', cnt: N}, ...]
+     */
+    List<Map<String, Object>> countDailyByResult(
+            @Param("sdate") String sdate,
+            @Param("edate") String edate);
 }

+ 11 - 0
src/main/java/com/jeesite/modules/mes/dao/MesRepairDao.java

@@ -3,6 +3,10 @@ package com.jeesite.modules.mes.dao;
 import com.jeesite.common.dao.CrudDao;
 import com.jeesite.common.mybatis.annotation.MyBatisDao;
 import com.jeesite.modules.mes.entity.MesRepair;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
 
 /**
  * 返工记录表DAO接口
@@ -13,4 +17,11 @@ import com.jeesite.modules.mes.entity.MesRepair;
 public interface MesRepairDao extends CrudDao<MesRepair> {
     MesRepair findInfo(MesRepair mesRepair);
 
+    /**
+     * 按返工白名单分组统计返工次数(指定时间段,按 create_date 过滤)
+     * 返回 [{title: ..., cnt: ...}, ...]
+     */
+    List<Map<String, Object>> countGroupByItemTitle(
+            @Param("sdate") String sdate,
+            @Param("edate") String edate);
 }

+ 7 - 0
src/main/java/com/jeesite/modules/mes/service/MesQualityService.java

@@ -83,5 +83,12 @@ public class MesQualityService extends CrudService<MesQualityDao, MesQuality> {
 	public void delete(MesQuality mesQuality) {
 		super.delete(mesQuality);
 	}
+
+	/**
+	 * 按天 + result(OK/NG) 分组统计抽检数量
+	 */
+	public java.util.List<java.util.Map<String, Object>> countDailyByResult(String sdate, String edate) {
+		return dao.countDailyByResult(sdate, edate);
+	}
 	
 }

+ 25 - 0
src/main/java/com/jeesite/modules/mes/service/MesRepairService.java

@@ -101,6 +101,31 @@ public class MesRepairService extends CrudService<MesRepairDao, MesRepair> {
 	 * @param sdate 开始时间(含)yyyy-MM-dd HH:mm:ss
 	 * @param edate 结束时间(不含)yyyy-MM-dd HH:mm:ss
 	 */
+	/**
+	 * 统计指定时间段内全产线的返工记录数量
+	 */
+	public Long countByDateRange(String sdate, String edate){
+		MesRepair q = new MesRepair();
+		q.getSqlMap().getWhere()
+				.and("create_date", QueryType.GTE, sdate)
+				.and("create_date", QueryType.LT, edate);
+		return super.findCount(q);
+	}
+
+	/**
+	 * 按返工白名单标题分组统计返工次数(用于大屏“不良类型柱状图”)
+	 * 返回 [{title, cnt}, ...]
+	 */
+	public java.util.List<java.util.Map<String, Object>> countGroupByItemTitle(String sdate, String edate) {
+		return dao.countGroupByItemTitle(sdate, edate);
+	}
+
+	/**
+	 * 统计指定产线、指定时间段内的返工记录数量(用于大屏“近七日产品质检”的不良统计)
+	 * @param lineSn 产线编号(MP/XT/ZP)
+	 * @param sdate 开始时间(含)yyyy-MM-dd HH:mm:ss
+	 * @param edate 结束时间(不含)yyyy-MM-dd HH:mm:ss
+	 */
 	public Long countByLineAndDate(String lineSn, String sdate, String edate){
 		MesRepair q = new MesRepair();
 		q.getSqlMap().getWhere()

+ 12 - 0
src/main/java/com/jeesite/modules/mes/service/MesScrapService.java

@@ -1,6 +1,7 @@
 package com.jeesite.modules.mes.service;
 
 import com.jeesite.common.entity.Page;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
 import com.jeesite.common.service.CrudService;
 import com.jeesite.modules.file.utils.FileUploadUtils;
 import com.jeesite.modules.mes.dao.MesScrapDao;
@@ -82,5 +83,16 @@ public class MesScrapService extends CrudService<MesScrapDao, MesScrap> {
 	public void delete(MesScrap mesScrap) {
 		super.delete(mesScrap);
 	}
+
+	/**
+	 * 统计指定时间段内的报废记录数量
+	 */
+	public Long countByDateRange(String sdate, String edate){
+		MesScrap q = new MesScrap();
+		q.getSqlMap().getWhere()
+				.and("create_date", QueryType.GTE, sdate)
+				.and("create_date", QueryType.LT, edate);
+		return super.findCount(q);
+	}
 	
 }

+ 160 - 0
src/main/java/com/jeesite/modules/mes/web/MesProductController.java

@@ -80,6 +80,15 @@ public class MesProductController extends BaseController {
     @Autowired
     private MesProcessAlarmService mesProcessAlarmService;
 
+    @Autowired
+    private MesRepairService mesRepairService;
+
+    @Autowired
+    private MesScrapService mesScrapService;
+
+    @Autowired
+    private MesQualityService mesQualityService;
+
 	/**
 	 * 获取数据
 	 */
@@ -619,6 +628,157 @@ public class MesProductController extends BaseController {
 		return resp;
 	}
 
+	/**
+	 * 综合大屏 - 当天返修数量 / 报废数量
+	 * 返修数据来自 mes_repair(返工记录表),报废数据来自 mes_scrap(报废记录表)
+	 */
+	@RequestMapping(value = "dashboardCount")
+	@ResponseBody
+	public CommonResp<Map<String, Object>> dashboardCount() {
+		CommonResp<Map<String, Object>> resp = new CommonResp<>();
+		LocalDate today = LocalDate.now();
+		String start = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00";
+		String end = today.plusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00";
+
+		Map<String, Object> map = MapUtils.newHashMap();
+		try {
+			Long repair = mesRepairService.countByDateRange(start, end);
+			Long scrap = mesScrapService.countByDateRange(start, end);
+			map.put("repair", repair == null ? 0 : repair);
+			map.put("scrap", scrap == null ? 0 : scrap);
+			resp.setData(map);
+			resp.setResult(Global.TRUE);
+		} catch (Exception e) {
+			logger.error("dashboardCount error: {}", e.getMessage(), e);
+			map.put("repair", 0);
+			map.put("scrap", 0);
+			resp.setData(map);
+			resp.setResult(Global.FALSE);
+			resp.setMessage(e.getMessage());
+		}
+		return resp;
+	}
+
+	/**
+	 * 综合大屏 - 不良类型柱状图:按返工白名单(mes_repair_items.title)分组统计返工次数(默认当天)
+	 * 返回 {labels:[], data:[], max: N}
+	 */
+	@RequestMapping(value = "defectTypeData")
+	@ResponseBody
+	public CommonResp<Map<String, Object>> defectTypeData() {
+		CommonResp<Map<String, Object>> resp = new CommonResp<>();
+		LocalDate today = LocalDate.now();
+		String start = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00";
+		String end = today.plusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00";
+
+		Map<String, Object> map = MapUtils.newHashMap();
+		try {
+			List<Map<String, Object>> rows = mesRepairService.countGroupByItemTitle(start, end);
+			List<String> labels = new ArrayList<>();
+			List<Integer> data = new ArrayList<>();
+			int max = 0;
+			if (rows != null) {
+				for (Map<String, Object> row : rows) {
+					Object t = row.get("title");
+					Object c = row.get("cnt");
+					String title = t == null ? "未分类" : String.valueOf(t);
+					int cnt = c == null ? 0 : ((Number) c).intValue();
+					labels.add(title);
+					data.add(cnt);
+					if (cnt > max) max = cnt;
+				}
+			}
+			// 留 20% 余量,避免最大柱顶到边
+			int yMax = (int) Math.ceil(Math.max(10, max) * 1.2);
+			map.put("labels", labels);
+			map.put("data", data);
+			map.put("max", yMax);
+			resp.setData(map);
+			resp.setResult(Global.TRUE);
+		} catch (Exception e) {
+			logger.error("defectTypeData error: {}", e.getMessage(), e);
+			map.put("labels", new ArrayList<>());
+			map.put("data", new ArrayList<>());
+			map.put("max", 10);
+			resp.setData(map);
+			resp.setResult(Global.FALSE);
+			resp.setMessage(e.getMessage());
+		}
+		return resp;
+	}
+
+	/**
+	 * 综合大屏 - 近七日产品抽检盘点:按天统计 mes_quality 的 OK/NG 次数
+	 * 返回 {labels:['6月7日',...], qualified:[OK次数...], defect:[NG次数...], max: N}
+	 */
+	@RequestMapping(value = "qualityInspectData")
+	@ResponseBody
+	public CommonResp<Map<String, Object>> qualityInspectData() {
+		CommonResp<Map<String, Object>> resp = new CommonResp<>();
+		Map<String, Object> map = MapUtils.newHashMap();
+		try {
+			DateTimeFormatter ymd = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+			DateTimeFormatter ymdHms = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+			LocalDate today = LocalDate.now();
+			LocalDate start = today.minusDays(6);   // 含今天,共7天
+			LocalDate end = today.plusDays(1);
+			String sdate = start.format(ymd) + " 00:00:00";
+			String edate = end.format(ymd) + " 00:00:00";
+
+			List<Map<String, Object>> rows = mesQualityService.countDailyByResult(sdate, edate);
+			// 用 day -> {OK:n, NG:n} 整理
+			java.util.Map<String, int[]> idx = new java.util.HashMap<>();
+			if (rows != null) {
+				for (Map<String, Object> row : rows) {
+					String day = row.get("day") == null ? "" : String.valueOf(row.get("day"));
+					String r = row.get("result") == null ? "" : String.valueOf(row.get("result")).trim().toUpperCase();
+					int cnt = row.get("cnt") == null ? 0 : ((Number) row.get("cnt")).intValue();
+					int[] arr = idx.computeIfAbsent(day, k -> new int[2]); // [ok, ng]
+					if ("OK".equals(r)) {
+						arr[0] += cnt;
+					} else if ("NG".equals(r)) {
+						arr[1] += cnt;
+					}
+					// 其它 result 值忽略,避免污染图表
+				}
+			}
+
+			List<String> labels = new ArrayList<>();
+			List<Integer> qualified = new ArrayList<>();
+			List<Integer> defect = new ArrayList<>();
+			int max = 0;
+			LocalDate d = start;
+			for (int i = 0; i < 7; i++) {
+				String key = d.format(ymd);
+				int[] arr = idx.getOrDefault(key, new int[2]);
+				labels.add((d.getMonthValue()) + "月" + d.getDayOfMonth() + "日");
+				qualified.add(arr[0]);
+				defect.add(arr[1]);
+				if (arr[0] > max) max = arr[0];
+				if (arr[1] > max) max = arr[1];
+				d = d.plusDays(1);
+			}
+			int yMax = (int) Math.ceil(Math.max(10, max) * 1.2);
+
+			map.put("labels", labels);
+			map.put("qualified", qualified);
+			map.put("defect", defect);
+			map.put("max", yMax);
+			resp.setData(map);
+			resp.setResult(Global.TRUE);
+		} catch (Exception e) {
+			logger.error("qualityInspectData error: {}", e.getMessage(), e);
+			map.put("labels", new ArrayList<>());
+			map.put("qualified", new ArrayList<>());
+			map.put("defect", new ArrayList<>());
+			map.put("max", 10);
+			resp.setData(map);
+			resp.setResult(Global.FALSE);
+			resp.setMessage(e.getMessage());
+		}
+		return resp;
+	}
+
 	@RequestMapping(value = "indexTj")
 	@ResponseBody
 	public CommonResp indexTj( HttpServletRequest req) {

+ 18 - 0
src/main/resources/mappings/modules/mes/MesQualityDao.xml

@@ -20,4 +20,22 @@
 		ORDER BY  id desc
 		LIMIT 1
 	</select>
+
+	<!-- 按天 + result(OK/NG) 分组统计抽检数量,用于大屏“近七日产品抽检盘点” -->
+	<select id="countDailyByResult" resultType="java.util.HashMap">
+		SELECT
+			DATE_FORMAT(a.create_date, '%Y-%m-%d') AS day,
+			UPPER(TRIM(IFNULL(a.result, ''))) AS result,
+			COUNT(1) AS cnt
+		FROM mes_quality a
+		<where>
+			<if test="sdate != null and sdate != ''">
+				AND a.create_date &gt;= #{sdate}
+			</if>
+			<if test="edate != null and edate != ''">
+				AND a.create_date &lt; #{edate}
+			</if>
+		</where>
+		GROUP BY DATE_FORMAT(a.create_date, '%Y-%m-%d'), UPPER(TRIM(IFNULL(a.result, '')))
+	</select>
 </mapper>

+ 19 - 0
src/main/resources/mappings/modules/mes/MesRepairDao.xml

@@ -20,4 +20,23 @@
 		ORDER BY ${sqlMap.order.toSql()}
 		LIMIT 1
 	</select>
+
+	<!-- 按返工白名单标题分组统计返工次数(用于大屏“不良类型柱状图”) -->
+	<select id="countGroupByItemTitle" resultType="java.util.HashMap">
+		SELECT
+			COALESCE(b.title, '未分类') AS title,
+			COUNT(1) AS cnt
+		FROM mes_repair a
+		LEFT JOIN mes_repair_items b ON b.id = a.item_id
+		<where>
+			<if test="sdate != null and sdate != ''">
+				AND a.create_date &gt;= #{sdate}
+			</if>
+			<if test="edate != null and edate != ''">
+				AND a.create_date &lt; #{edate}
+			</if>
+		</where>
+		GROUP BY b.title
+		ORDER BY cnt DESC
+	</select>
 </mapper>

+ 67 - 4
src/main/resources/views/modules/mes/mesScreen3.html

@@ -637,7 +637,7 @@
 			</div>
 			<!-- 面板2: 近七日产品检验盘点 -->
 			<div class="mes3-panel mes3-panel-left2">
-				<div class="panel-header">近七日产品检验盘点</div>
+				<div class="panel-header">近七日产品抽检盘点</div>
 				<div class="panel-body">
 					<canvas id="chartLeft2" class="mes3-chart"></canvas>
 				</div>
@@ -1171,7 +1171,7 @@
 		ctx.fillStyle = '#ffffff';
 		ctx.font = '12px Microsoft YaHei';
 		ctx.textAlign = 'left';
-		ctx.fillText('产出', padL + 58, 18);
+		ctx.fillText('合格', padL + 58, 18);
 		ctx.fillStyle = '#00C8FF';
 		ctx.fillRect(padL + 110, 8, 12, 12);
 		ctx.fillStyle = '#ffffff';
@@ -1476,15 +1476,18 @@
 			dataType: 'json',
 			data: {
 				pageNo: 1,
-				pageSize: 50
+				pageSize: 50,
+				state: '0' // 只显示待处理的报警
 			},
 			success: function(resp) {
 				var rows = extractList(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: i + 1, text: typ });
+					alerts.push({ no: alerts.length + 1, text: typ });
 				}
 				mockData.alerts = alerts;
 				renderAlerts();
@@ -1635,6 +1638,63 @@
 		return t >= day.startMs && t <= day.endMs;
 	}
 
+	// 综合大屏 - 当天返修数量(mes_repair) / 报废数量(mes_scrap)
+	function updateRepairScrapCountByApi() {
+		$.ajax({
+			url: '${ctx}/mes/mesProduct/dashboardCount',
+			type: 'POST',
+			dataType: 'json',
+			success: function(resp) {
+				if (!resp || resp.result !== 'true' || !resp.data) {
+					return;
+				}
+				mockData.cards = mockData.cards || {};
+				mockData.cards.repairCount = Number(resp.data.repair) || 0;
+				mockData.cards.scrapCount = Number(resp.data.scrap) || 0;
+				renderTextData();
+			}
+		});
+	}
+
+	// 不良类型柱状图:按返工白名单(item_id->title)分组统计当天返工次数
+	function updateDefectTypeByApi() {
+		$.ajax({
+			url: '${ctx}/mes/mesProduct/defectTypeData',
+			type: 'POST',
+			dataType: 'json',
+			success: function(resp) {
+				if (!resp || resp.result !== 'true' || !resp.data) return;
+				var d = resp.data;
+				mockData.defectType = {
+					labels: d.labels || [],
+					data: d.data || [],
+					max: Number(d.max) || 10
+				};
+				drawAllCharts();
+			}
+		});
+	}
+
+	// 近七日产品抽检盘点:按天统计 mes_quality 的 OK(合格) / NG(不良) 次数
+	function updateQualityInspectByApi() {
+		$.ajax({
+			url: '${ctx}/mes/mesProduct/qualityInspectData',
+			type: 'POST',
+			dataType: 'json',
+			success: function(resp) {
+				if (!resp || resp.result !== 'true' || !resp.data) return;
+				var d = resp.data;
+				mockData.qualityInspect = {
+					labels: d.labels || [],
+					produced: d.qualified || [], // 沿用原 produced 字段渲染(柱状图代码不动)
+					defect: d.defect || [],
+					max: Number(d.max) || 10
+				};
+				drawAllCharts();
+			}
+		});
+	}
+
 	function updateActualProductionByApi() {
 		var dayRange = getCalendarDayUpdateDateRange();
 		var pageSize = 3000;
@@ -1785,6 +1845,9 @@
 		updateActualProductionByApi();
 		updateProductTrend7DaysByApi();
 		updateDeviceAlarmAlertsByApi();
+		updateRepairScrapCountByApi();
+		updateDefectTypeByApi();
+		updateQualityInspectByApi();
 		renderFaultRank();
 		renderAlerts();
 		updateHourlyUpDownByApi();

+ 4 - 2
src/main/resources/views/modules/mes/mesScreen4.html

@@ -1083,15 +1083,17 @@
 			dataType: 'json',
 			data: {
 				pageNo: 1,
-				pageSize: 50
+				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: i + 1, text: typ });
+					alerts.push({ no: alerts.length + 1, text: typ });
 				}
 				mockData.alerts = alerts;
 				renderAlerts();

+ 4 - 2
src/main/resources/views/modules/mes/mesScreen5.html

@@ -1171,15 +1171,17 @@
 			dataType: 'json',
 			data: {
 				pageNo: 1,
-				pageSize: 50
+				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: i + 1, text: typ });
+					alerts.push({ no: alerts.length + 1, text: typ });
 				}
 				mockData.alerts = alerts;
 				renderAlerts();

+ 4 - 2
src/main/resources/views/modules/mes/mesScreen6.html

@@ -1171,15 +1171,17 @@
 			dataType: 'json',
 			data: {
 				pageNo: 1,
-				pageSize: 50
+				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: i + 1, text: typ });
+					alerts.push({ no: alerts.length + 1, text: typ });
 				}
 				mockData.alerts = alerts;
 				renderAlerts();