zhanghe 5 mesiacov pred
rodič
commit
7fc85a2a98

+ 1 - 1
src/main/java/com/jeesite/modules/erp/dao/MesProductOrderDao.java

@@ -12,5 +12,5 @@ import com.jeesite.modules.erp.entity.MesProductOrder;
 @MyBatisDao
 public interface MesProductOrderDao extends CrudDao<MesProductOrder> {
 
-    MesProductOrder findBySn(String sn,String start);
+    MesProductOrder findBySn(String sn,String state);
 }

+ 16 - 0
src/main/java/com/jeesite/modules/mes/service/MesInboundService.java

@@ -6,6 +6,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import com.jeesite.common.entity.Page;
 import com.jeesite.common.service.CrudService;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
 import com.jeesite.modules.mes.entity.MesInbound;
 import com.jeesite.modules.mes.dao.MesInboundDao;
 import com.jeesite.common.service.ServiceException;
@@ -133,5 +134,20 @@ public class MesInboundService extends CrudService<MesInboundDao, MesInbound> {
 	public void delete(MesInbound mesInbound) {
 		super.delete(mesInbound);
 	}
+
+	/**
+	 * 统计指定产线、指定时间段内的入库数量(用于大屏“近七日产品质检”的产出统计)
+	 * @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){
+		MesInbound q = new MesInbound();
+		q.getSqlMap().getWhere()
+				.and("line_sn", QueryType.EQ, lineSn)
+				.and("create_date", QueryType.GTE, sdate)
+				.and("create_date", QueryType.LT, edate);
+		return super.findCount(q);
+	}
 	
 }

+ 75 - 1
src/main/java/com/jeesite/modules/mes/service/MesProductRecordService.java

@@ -925,6 +925,7 @@ public class MesProductRecordService extends CrudService<MesProductRecordDao, Me
 //		paramsResp1.setResult("OK");
 //		paramsResp1.setVal(userCode);
 //		paramsResps.add(paramsResp1); // 绑定用户
+
 		List<BindMaterialResp> bmlists = new ArrayList<>();
 		updateRecordResult(sn, oprno, craft, materielSn, content, userCode, paramsResps,lineSn,true,bmlists,null);
 
@@ -937,7 +938,9 @@ public class MesProductRecordService extends CrudService<MesProductRecordDao, Me
 			mesProductOp.setSn(sn);
 			mesProductOp.setLineSn(lineSn);
 		}
-		mesProductHbDao.insertBatch(oplists);
+		if(oplists != null && !oplists.isEmpty()){
+			mesProductHbDao.insertBatch(oplists);
+		}
 
 	}
 
@@ -1318,6 +1321,77 @@ public class MesProductRecordService extends CrudService<MesProductRecordDao, Me
 		return ret;
 	}
 
+	/**
+	 * 实际产能(当天产能):统计今天 00:00 ~ 次日 00:00 之间,指定产线、各工位的产能
+	 * 统计口径与“小时产能”一致(craft=100000 且结果不为 UDF)
+	 */
+	public Map<String, Integer> getCurrentDayCapacityStats(String lineSn, List<String> oprnos) {
+		Map<String, Integer> ret = MapUtils.newHashMap();
+		if (StringUtils.isBlank(lineSn) || oprnos == null || oprnos.isEmpty()) {
+			return ret;
+		}
+		Calendar calendar = Calendar.getInstance();
+		calendar.set(Calendar.HOUR_OF_DAY, 0);
+		calendar.set(Calendar.MINUTE, 0);
+		calendar.set(Calendar.SECOND, 0);
+		calendar.set(Calendar.MILLISECOND, 0);
+		Date startTime = calendar.getTime();        // 今天 00:00:00
+		calendar.add(Calendar.DAY_OF_MONTH, 1);
+		Date endTime = calendar.getTime();          // 次日 00:00:00
+		for (String oprno : oprnos) {
+			if (StringUtils.isBlank(oprno)) {
+				continue;
+			}
+			String formatOprno = CommonUitl.formatOprno(oprno.trim());
+			Long count = mesProductRecordDao.countHourCapacityByLineAndOprnoPrefix(
+					lineSn.trim(), formatOprno, startTime, endTime);
+			ret.put(formatOprno, count == null ? 0 : count.intValue());
+		}
+		return ret;
+	}
+
+	/**
+	 * 当班产能:根据班次生产计划管理中配置的当前班次时间段进行统计
+	 * 班次时间段取自 {@link MesShiftService#getCurShift()}(当前所处班次的开始/结束时间)
+	 * 未配置班次或不在任何班次时间内时,返回 0
+	 */
+	public Map<String, Integer> getCurrentShiftCapacityStats(String lineSn, List<String> oprnos) {
+		Map<String, Integer> ret = MapUtils.newHashMap();
+		if (StringUtils.isBlank(lineSn) || oprnos == null || oprnos.isEmpty()) {
+			return ret;
+		}
+		// 当前班次时间段(来自班次生产计划管理的班次设置)
+		MesShiftDataResp curShift = mesShiftService.getCurShift();
+		Date startTime = null;
+		Date endTime = null;
+		if (!ObjectUtils.isEmpty(curShift)
+				&& StringUtils.isNotBlank(curShift.getStart())
+				&& StringUtils.isNotBlank(curShift.getEnd())) {
+			try {
+				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+				startTime = sdf.parse(curShift.getStart());
+				endTime = sdf.parse(curShift.getEnd());
+			} catch (Exception e) {
+				startTime = null;
+				endTime = null;
+			}
+		}
+		for (String oprno : oprnos) {
+			if (StringUtils.isBlank(oprno)) {
+				continue;
+			}
+			String formatOprno = CommonUitl.formatOprno(oprno.trim());
+			int count = 0;
+			if (startTime != null && endTime != null) {
+				Long c = mesProductRecordDao.countHourCapacityByLineAndOprnoPrefix(
+						lineSn.trim(), formatOprno, startTime, endTime);
+				count = c == null ? 0 : c.intValue();
+			}
+			ret.put(formatOprno, count);
+		}
+		return ret;
+	}
+
 	private void fillHourlyCounts(List<Map<String, Object>> rows, int[] bucket) {
 		if (rows == null) {
 			return;

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

@@ -94,4 +94,19 @@ public class MesRepairService extends CrudService<MesRepairDao, MesRepair> {
 		Long jpp1 = super.findCount(mesProductRecord);
 		return String.valueOf(jpp1);
 	}
+
+	/**
+	 * 统计指定产线、指定时间段内的返工记录数量(用于大屏“近七日产品质检”的不良统计)
+	 * @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()
+				.and("line_sn", QueryType.EQ, lineSn)
+				.and("create_date", QueryType.GTE, sdate)
+				.and("create_date", QueryType.LT, edate);
+		return super.findCount(q);
+	}
 }

+ 181 - 0
src/main/java/com/jeesite/modules/mes/web/MesProductRecordController.java

@@ -183,6 +183,9 @@ public class MesProductRecordController extends BaseController {
 	private MesRepairService mesRepairService;
 
 	@Autowired
+	private MesInboundService mesInboundService;
+
+	@Autowired
 	private MesProductModifyRecordService mesProductModifyRecordService;
 
 	@Autowired
@@ -402,6 +405,184 @@ public class MesProductRecordController extends BaseController {
 	}
 
 	/**
+	 * 实际产能(当天产能):统计今天 00:00 至次日 00:00 指定产线、各工位的产能
+	 */
+	@RequestMapping(value = "dayCapacityData")
+	@ResponseBody
+	public CommonResp<Map<String, Integer>> dayCapacityData(HttpServletRequest request) {
+		CommonResp<Map<String, Integer>> resp = new CommonResp<>();
+		String lineSn = StringUtils.trimToEmpty(request.getParameter("lineSn"));
+		String oprnos = StringUtils.trimToEmpty(request.getParameter("oprnos"));
+		if (StringUtils.isBlank(lineSn) || StringUtils.isBlank(oprnos)) {
+			resp.setResult("false");
+			resp.setMessage("lineSn、oprnos 不能为空");
+			return resp;
+		}
+		try {
+			List<String> oprnoList = new ArrayList<>();
+			String[] arr = oprnos.split(",");
+			for (String item : arr) {
+				String oprno = StringUtils.trimToEmpty(item);
+				if (StringUtils.isNotBlank(oprno)) {
+					oprnoList.add(oprno);
+				}
+			}
+			resp.setData(mesProductRecordService.getCurrentDayCapacityStats(lineSn, oprnoList));
+			resp.setResult("true");
+		} catch (Exception e) {
+			logger.error(e.getMessage(), e);
+			resp.setResult("false");
+			resp.setMessage("查询失败:" + e.getMessage());
+		}
+		return resp;
+	}
+
+	/**
+	 * 当班产能:根据班次生产计划管理的当前班次时间段统计指定产线、各工位的产能
+	 */
+	@RequestMapping(value = "shiftCapacityData")
+	@ResponseBody
+	public CommonResp<Map<String, Integer>> shiftCapacityData(HttpServletRequest request) {
+		CommonResp<Map<String, Integer>> resp = new CommonResp<>();
+		String lineSn = StringUtils.trimToEmpty(request.getParameter("lineSn"));
+		String oprnos = StringUtils.trimToEmpty(request.getParameter("oprnos"));
+		if (StringUtils.isBlank(lineSn) || StringUtils.isBlank(oprnos)) {
+			resp.setResult("false");
+			resp.setMessage("lineSn、oprnos 不能为空");
+			return resp;
+		}
+		try {
+			List<String> oprnoList = new ArrayList<>();
+			String[] arr = oprnos.split(",");
+			for (String item : arr) {
+				String oprno = StringUtils.trimToEmpty(item);
+				if (StringUtils.isNotBlank(oprno)) {
+					oprnoList.add(oprno);
+				}
+			}
+			resp.setData(mesProductRecordService.getCurrentShiftCapacityStats(lineSn, oprnoList));
+			resp.setResult("true");
+		} catch (Exception e) {
+			logger.error(e.getMessage(), e);
+			resp.setResult("false");
+			resp.setMessage("查询失败:" + e.getMessage());
+		}
+		return resp;
+	}
+
+	/**
+	 * 近七日产品质检数据分析(按产线)
+	 * 产出:半成品入库管理(mes_inbound) 按产线、按天统计的入库数量
+	 * 不良:返工记录表(mes_repair) 按产线、按天统计的返工数量
+	 * 返回最近 7 天(含今天)的数据,labels/produced/defect 三个数组一一对应
+	 */
+	@RequestMapping(value = "weekQualityData")
+	@ResponseBody
+	public CommonResp<Map<String, Object>> weekQualityData(HttpServletRequest request) {
+		CommonResp<Map<String, Object>> resp = new CommonResp<>();
+		String lineSn = StringUtils.trimToEmpty(request.getParameter("lineSn"));
+		if (StringUtils.isBlank(lineSn)) {
+			resp.setResult("false");
+			resp.setMessage("lineSn 不能为空");
+			return resp;
+		}
+		try {
+			List<String> labels = new ArrayList<>();
+			List<Integer> produced = new ArrayList<>();
+			List<Integer> defect = new ArrayList<>();
+			SimpleDateFormat dayFmt = new SimpleDateFormat("yyyy-MM-dd");
+			Calendar cal = Calendar.getInstance();
+			cal.set(Calendar.HOUR_OF_DAY, 0);
+			cal.set(Calendar.MINUTE, 0);
+			cal.set(Calendar.SECOND, 0);
+			cal.set(Calendar.MILLISECOND, 0);
+			cal.add(Calendar.DAY_OF_MONTH, -6);
+			for (int i = 0; i < 7; i++) {
+				Calendar dayStartCal = (Calendar) cal.clone();
+				Calendar dayEndCal = (Calendar) cal.clone();
+				dayEndCal.add(Calendar.DAY_OF_MONTH, 1);
+				String dayStartStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(dayStartCal.getTime());
+				String dayEndStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(dayEndCal.getTime());
+
+				int m = dayStartCal.get(Calendar.MONTH) + 1;
+				int d = dayStartCal.get(Calendar.DAY_OF_MONTH);
+				labels.add(m + "月" + d + "日");
+
+				Long outNum = mesInboundService.countByLineAndDate(lineSn, dayStartStr, dayEndStr);
+				Long ngNum = mesRepairService.countByLineAndDate(lineSn, dayStartStr, dayEndStr);
+				produced.add(outNum == null ? 0 : outNum.intValue());
+				defect.add(ngNum == null ? 0 : ngNum.intValue());
+
+				cal.add(Calendar.DAY_OF_MONTH, 1);
+			}
+			Map<String, Object> data = MapUtils.newHashMap();
+			data.put("labels", labels);
+			data.put("produced", produced);
+			data.put("defect", defect);
+			resp.setData(data);
+			resp.setResult("true");
+		} catch (Exception e) {
+			logger.error(e.getMessage(), e);
+			resp.setResult("false");
+			resp.setMessage("查询失败:" + e.getMessage());
+		}
+		return resp;
+	}
+
+	/**
+	 * 各月产量统计图(按产线)
+	 * 按月统计半成品入库管理(mes_inbound) 的入库数量,返回当年 1~12 月数据
+	 */
+	@RequestMapping(value = "monthlyProductData")
+	@ResponseBody
+	public CommonResp<Map<String, Object>> monthlyProductData(HttpServletRequest request) {
+		CommonResp<Map<String, Object>> resp = new CommonResp<>();
+		String lineSn = StringUtils.trimToEmpty(request.getParameter("lineSn"));
+		if (StringUtils.isBlank(lineSn)) {
+			resp.setResult("false");
+			resp.setMessage("lineSn 不能为空");
+			return resp;
+		}
+		try {
+			// 年份:默认当前年,支持传入 year 参数
+			String yearParam = StringUtils.trimToEmpty(request.getParameter("year"));
+			int year;
+			if (StringUtils.isNotBlank(yearParam)) {
+				year = Integer.parseInt(yearParam);
+			} else {
+				year = Calendar.getInstance().get(Calendar.YEAR);
+			}
+			List<String> labels = new ArrayList<>();
+			List<Integer> data = new ArrayList<>();
+			SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+			for (int month = 0; month < 12; month++) {
+				Calendar startCal = Calendar.getInstance();
+				startCal.clear();
+				startCal.set(year, month, 1, 0, 0, 0);
+				Calendar endCal = (Calendar) startCal.clone();
+				endCal.add(Calendar.MONTH, 1);  // 下个月 1 号 00:00:00
+				String startStr = fmt.format(startCal.getTime());
+				String endStr = fmt.format(endCal.getTime());
+
+				labels.add((month + 1) + "月");
+				Long num = mesInboundService.countByLineAndDate(lineSn, startStr, endStr);
+				data.add(num == null ? 0 : num.intValue());
+			}
+			Map<String, Object> result = MapUtils.newHashMap();
+			result.put("labels", labels);
+			result.put("data", data);
+			result.put("year", year);
+			resp.setData(result);
+			resp.setResult("true");
+		} catch (Exception e) {
+			logger.error(e.getMessage(), e);
+			resp.setResult("false");
+			resp.setMessage("查询失败:" + e.getMessage());
+		}
+		return resp;
+	}
+
+	/**
 	 * 查看编辑表单
 	 */
 	@RequiresPermissions("mes:mesProductRecord:view")

+ 2 - 2
src/main/resources/mappings/modules/erp/MesProductOrderDao.xml

@@ -21,11 +21,11 @@
 
                 <where>
                     sn = #{sn}
-                </where>
+
                 <if test="state != null and state != ''">
                     and state = #{state}
                 </if>
-
+                </where>
             </select>
 
 </mapper>

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

@@ -929,22 +929,30 @@
 		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/hourlyCapacityData',
+			url: '${ctx}/mes/mesProductRecord/' + action,
 			type: 'POST',
 			dataType: 'json',
 			data: {
-				lineSn: 'MP',
+				lineSn: lineSn,
 				oprnos: oprnos.join(',')
 			},
 			success: function(resp) {
 				if (!resp || resp.result !== 'true' || !resp.data) {
 					return;
 				}
-				var hourMap = resp.data || {};
+				var map = resp.data || {};
+				var list = mockData.opTable || [];
 				for (var i = 0; i < list.length; i++) {
 					var code = list[i].code || '';
-					list[i].hour = Number(hourMap[code]) || 0;
+					list[i][field] = Number(map[code]) || 0;
 				}
 				renderTable();
 			}
@@ -968,6 +976,80 @@
 			}
 		});
 	}
+
+	// 近七日产品质检数据分析(产出=半成品入库,不良=返工记录),按产线 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 = {
@@ -1202,6 +1284,8 @@
 		updateActualProductionByApi();
 		updateDeviceAlarmAlertsByApi();
 		updateHourlyUpDownByApi();
+		updateWeekQualityByApi();
+		updateMonthlyProductByApi();
 		drawAllCharts();
 	}
 

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

@@ -1017,28 +1017,110 @@
 		if (!oprnos.length) {
 			return;
 		}
+		fetchCapacityInto('hourlyCapacityData', 'XT', oprnos, 'hour');
+		fetchCapacityInto('dayCapacityData', 'XT', oprnos, 'real');
+		fetchCapacityInto('shiftCapacityData', 'XT', oprnos, 'shift');
+	}
+
+	// 通用:拉取产能数据并写入表格指定字段(hour=小时产能, real=实际/当天产能, shift=当班产能)
+	function fetchCapacityInto(action, lineSn, oprnos, field) {
 		$.ajax({
-			url: '${ctx}/mes/mesProductRecord/hourlyCapacityData',
+			url: '${ctx}/mes/mesProductRecord/' + action,
 			type: 'POST',
 			dataType: 'json',
 			data: {
-				lineSn: 'XT',
+				lineSn: lineSn,
 				oprnos: oprnos.join(',')
 			},
 			success: function(resp) {
 				if (!resp || resp.result !== 'true' || !resp.data) {
 					return;
 				}
-				var hourMap = resp.data || {};
+				var map = resp.data || {};
+				var list = mockData.opTable || [];
 				for (var i = 0; i < list.length; i++) {
 					var code = list[i].code || '';
-					list[i].hour = Number(hourMap[code]) || 0;
+					list[i][field] = Number(map[code]) || 0;
 				}
 				renderTable();
 			}
 		});
 	}
 
+	// 近七日产品质检数据分析(产出=半成品入库,不良=返工记录),按产线 XT 统计
+	function updateWeekQualityByApi() {
+		$.ajax({
+			url: '${ctx}/mes/mesProductRecord/weekQualityData',
+			type: 'POST',
+			dataType: 'json',
+			data: { lineSn: 'XT' },
+			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();
+			}
+		});
+	}
+
+	// 各月产量统计图(半成品入库管理按月统计),按产线 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 updateLatestPlanProductionByApi() {
 		$.ajax({
 			url: '${ctx}/mes/mesPlan/latestPlanNums',
@@ -1292,6 +1374,8 @@
 		updateActualProductionByApi();
 		updateDeviceAlarmAlertsByApi();
 		updateHourlyUpDownByApi();
+		updateWeekQualityByApi();
+		updateMonthlyProductByApi();
 		drawAllCharts();
 	}
 

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

@@ -1017,28 +1017,110 @@
 		if (!oprnos.length) {
 			return;
 		}
+		fetchCapacityInto('hourlyCapacityData', 'ZP', oprnos, 'hour');
+		fetchCapacityInto('dayCapacityData', 'ZP', oprnos, 'real');
+		fetchCapacityInto('shiftCapacityData', 'ZP', oprnos, 'shift');
+	}
+
+	// 通用:拉取产能数据并写入表格指定字段(hour=小时产能, real=实际/当天产能, shift=当班产能)
+	function fetchCapacityInto(action, lineSn, oprnos, field) {
 		$.ajax({
-			url: '${ctx}/mes/mesProductRecord/hourlyCapacityData',
+			url: '${ctx}/mes/mesProductRecord/' + action,
 			type: 'POST',
 			dataType: 'json',
 			data: {
-				lineSn: 'ZP',
+				lineSn: lineSn,
 				oprnos: oprnos.join(',')
 			},
 			success: function(resp) {
 				if (!resp || resp.result !== 'true' || !resp.data) {
 					return;
 				}
-				var hourMap = resp.data || {};
+				var map = resp.data || {};
+				var list = mockData.opTable || [];
 				for (var i = 0; i < list.length; i++) {
 					var code = list[i].code || '';
-					list[i].hour = Number(hourMap[code]) || 0;
+					list[i][field] = Number(map[code]) || 0;
 				}
 				renderTable();
 			}
 		});
 	}
 
+	// 近七日产品质检数据分析(产出=半成品入库,不良=返工记录),按产线 ZP 统计
+	function updateWeekQualityByApi() {
+		$.ajax({
+			url: '${ctx}/mes/mesProductRecord/weekQualityData',
+			type: 'POST',
+			dataType: 'json',
+			data: { lineSn: 'ZP' },
+			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();
+			}
+		});
+	}
+
+	// 各月产量统计图(半成品入库管理按月统计),按产线 ZP
+	function updateMonthlyProductByApi() {
+		$.ajax({
+			url: '${ctx}/mes/mesProductRecord/monthlyProductData',
+			type: 'POST',
+			dataType: 'json',
+			data: { lineSn: 'ZP' },
+			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 updateLatestPlanProductionByApi() {
 		$.ajax({
 			url: '${ctx}/mes/mesPlan/latestPlanNums',
@@ -1292,6 +1374,8 @@
 		updateActualProductionByApi();
 		updateDeviceAlarmAlertsByApi();
 		updateHourlyUpDownByApi();
+		updateWeekQualityByApi();
+		updateMonthlyProductByApi();
 		drawAllCharts();
 	}