|
|
@@ -0,0 +1,277 @@
|
|
|
+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.mes.dao.MesDailyPieceworkDao;
|
|
|
+import com.jeesite.modules.mes.entity.MesDailyPiecework;
|
|
|
+import com.jeesite.modules.mes.entity.MesLineProcess;
|
|
|
+import com.jeesite.modules.mes.entity.MesScreenPlan;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.text.DecimalFormat;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Calendar;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 每日计件统计Service
|
|
|
+ * @author system
|
|
|
+ * @version 2025-12-16
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class MesDailyPieceworkService extends CrudService<MesDailyPieceworkDao, MesDailyPiecework> {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private MesScreenPlanService mesScreenPlanService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private MesLineProcessService mesLineProcessService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private MesProductRecordService mesProductRecordService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询分页数据(完全按照大屏逻辑)
|
|
|
+ * @param mesDailyPiecework 查询条件
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Page<MesDailyPiecework> findPage(MesDailyPiecework mesDailyPiecework) {
|
|
|
+ // 设置默认查询条件(昨天和前天,共2天)
|
|
|
+ setDefaultDateRange(mesDailyPiecework);
|
|
|
+
|
|
|
+ // 生成完整的数据列表(和大屏一样的逻辑)
|
|
|
+ List<MesDailyPiecework> fullList = generateDataList(mesDailyPiecework);
|
|
|
+
|
|
|
+ // 手动分页
|
|
|
+ Page<MesDailyPiecework> page = mesDailyPiecework.getPage();
|
|
|
+ if (page == null) {
|
|
|
+ page = new Page<>();
|
|
|
+ page.setPageNo(1);
|
|
|
+ page.setPageSize(20);
|
|
|
+ }
|
|
|
+
|
|
|
+ page.setCount(fullList.size());
|
|
|
+
|
|
|
+ int pageNo = page.getPageNo();
|
|
|
+ int pageSize = page.getPageSize();
|
|
|
+ int fromIndex = (pageNo - 1) * pageSize;
|
|
|
+ int toIndex = Math.min(fromIndex + pageSize, fullList.size());
|
|
|
+
|
|
|
+ if (fromIndex < fullList.size()) {
|
|
|
+ page.setList(fullList.subList(fromIndex, toIndex));
|
|
|
+ } else {
|
|
|
+ page.setList(new ArrayList<>());
|
|
|
+ }
|
|
|
+
|
|
|
+ return page;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按天分批查询分页数据(优化性能)
|
|
|
+ * @param mesDailyPiecework 查询条件
|
|
|
+ * @param dayOffset 天数偏移,1=昨天,2=前天,null=按原逻辑查询2天
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public Page<MesDailyPiecework> findPageByDay(MesDailyPiecework mesDailyPiecework, Integer dayOffset) {
|
|
|
+ // 如果没有指定dayOffset,按原逻辑查询
|
|
|
+ if (dayOffset == null) {
|
|
|
+ return findPage(mesDailyPiecework);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据dayOffset设置单天查询范围
|
|
|
+ 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, -dayOffset); // 往前推指定天数
|
|
|
+
|
|
|
+ // 设置为查询单天
|
|
|
+ mesDailyPiecework.setStartDate(cal.getTime());
|
|
|
+ mesDailyPiecework.setEndDate(cal.getTime());
|
|
|
+
|
|
|
+ // 生成该天的数据列表
|
|
|
+ List<MesDailyPiecework> fullList = generateDataList(mesDailyPiecework);
|
|
|
+
|
|
|
+ // 手动分页
|
|
|
+ Page<MesDailyPiecework> page = mesDailyPiecework.getPage();
|
|
|
+ if (page == null) {
|
|
|
+ page = new Page<>();
|
|
|
+ page.setPageNo(1);
|
|
|
+ page.setPageSize(20);
|
|
|
+ }
|
|
|
+
|
|
|
+ page.setCount(fullList.size());
|
|
|
+
|
|
|
+ int pageNo = page.getPageNo();
|
|
|
+ int pageSize = page.getPageSize();
|
|
|
+ int fromIndex = (pageNo - 1) * pageSize;
|
|
|
+ int toIndex = Math.min(fromIndex + pageSize, fullList.size());
|
|
|
+
|
|
|
+ if (fromIndex < fullList.size()) {
|
|
|
+ page.setList(fullList.subList(fromIndex, toIndex));
|
|
|
+ } else {
|
|
|
+ page.setList(new ArrayList<>());
|
|
|
+ }
|
|
|
+
|
|
|
+ return page;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询列表数据(用于导出)
|
|
|
+ * @param mesDailyPiecework
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<MesDailyPiecework> findList(MesDailyPiecework mesDailyPiecework) {
|
|
|
+ // 导出时如果没有指定日期,则导出上一个月的数据
|
|
|
+ if (mesDailyPiecework.getStartDate() == null && mesDailyPiecework.getEndDate() == null) {
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
+
|
|
|
+ // 设置为上个月的最后一天
|
|
|
+ cal.set(Calendar.DAY_OF_MONTH, 1); // 本月1号
|
|
|
+ cal.add(Calendar.DAY_OF_MONTH, -1); // 上月最后一天
|
|
|
+ cal.set(Calendar.HOUR_OF_DAY, 0);
|
|
|
+ cal.set(Calendar.MINUTE, 0);
|
|
|
+ cal.set(Calendar.SECOND, 0);
|
|
|
+ cal.set(Calendar.MILLISECOND, 0);
|
|
|
+ mesDailyPiecework.setEndDate(cal.getTime());
|
|
|
+
|
|
|
+ // 设置为上个月的第一天
|
|
|
+ cal.set(Calendar.DAY_OF_MONTH, 1); // 上月1号
|
|
|
+ mesDailyPiecework.setStartDate(cal.getTime());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成完整的数据列表(和大屏一样的逻辑)
|
|
|
+ return generateDataList(mesDailyPiecework);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置默认日期范围(昨天和前天,共2天)
|
|
|
+ */
|
|
|
+ private void setDefaultDateRange(MesDailyPiecework mesDailyPiecework) {
|
|
|
+ if (mesDailyPiecework.getStartDate() == null && mesDailyPiecework.getEndDate() == null) {
|
|
|
+ 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, -1); // 往前推1天,昨天
|
|
|
+ mesDailyPiecework.setEndDate(cal.getTime()); // 昨天 00:00:00
|
|
|
+
|
|
|
+ cal.add(Calendar.DAY_OF_MONTH, -1); // 再往前推1天,前天
|
|
|
+ mesDailyPiecework.setStartDate(cal.getTime()); // 前天 00:00:00
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成数据列表(完全按照大屏逻辑)
|
|
|
+ */
|
|
|
+ private List<MesDailyPiecework> generateDataList(MesDailyPiecework mesDailyPiecework) {
|
|
|
+ List<MesDailyPiecework> resultList = new ArrayList<>();
|
|
|
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
+ DecimalFormat df = new DecimalFormat("0.00");
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+
|
|
|
+ // 1. 查询所有主工位(和大屏一样)
|
|
|
+ MesLineProcess mesLineProcess = new MesLineProcess();
|
|
|
+ mesLineProcess.setStatus("0");
|
|
|
+ mesLineProcess.getSqlMap().getWhere().and("pid", QueryType.IS_NULL, "");
|
|
|
+ List<MesLineProcess> processList = mesLineProcessService.findList(mesLineProcess);
|
|
|
+
|
|
|
+ // 如果指定了工位号,则过滤
|
|
|
+ if (mesDailyPiecework.getOprno() != null && !mesDailyPiecework.getOprno().isEmpty()) {
|
|
|
+ String searchOprno = mesDailyPiecework.getOprno();
|
|
|
+ processList.removeIf(p -> !p.getOprno().contains(searchOprno));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 生成日期列表
|
|
|
+ Calendar startCal = Calendar.getInstance();
|
|
|
+ startCal.setTime(mesDailyPiecework.getStartDate());
|
|
|
+ Calendar endCal = Calendar.getInstance();
|
|
|
+ endCal.setTime(mesDailyPiecework.getEndDate());
|
|
|
+
|
|
|
+ // 3. 遍历每一天
|
|
|
+ while (!startCal.after(endCal)) {
|
|
|
+ Date currentDate = startCal.getTime();
|
|
|
+ String dateStr = sdf.format(currentDate);
|
|
|
+
|
|
|
+ // 计算当天的时间范围(08:00到次日08:00,和大屏一样)
|
|
|
+ LocalDate localDate = LocalDate.parse(dateStr, formatter);
|
|
|
+ LocalDate tomorrow = localDate.plusDays(1);
|
|
|
+ String sdate = dateStr + " 08:00:00";
|
|
|
+ String edate = tomorrow.format(formatter) + " 08:00:00";
|
|
|
+
|
|
|
+ // 获取当天的计划
|
|
|
+ MesScreenPlan plan = mesScreenPlanService.getPlan(dateStr);
|
|
|
+
|
|
|
+ // 4. 遍历每个工位(和大屏一样)
|
|
|
+ for (MesLineProcess process : processList) {
|
|
|
+ MesDailyPiecework item = new MesDailyPiecework();
|
|
|
+ item.setStatDate(currentDate);
|
|
|
+ item.setStatDateStr(dateStr);
|
|
|
+ item.setOprno(process.getOprno());
|
|
|
+ item.setProcessTitle(process.getTitle());
|
|
|
+ item.setLineSn(process.getLineSn());
|
|
|
+
|
|
|
+ // 调用和大屏一样的方法获取数据
|
|
|
+ String dayTotal = mesProductRecordService.getSj(process.getOprno(), process.getLineSn(), sdate, edate);
|
|
|
+ int actualCount = Integer.parseInt(dayTotal);
|
|
|
+ item.setActualCount(actualCount);
|
|
|
+
|
|
|
+ String dayOks = mesProductRecordService.getSjOk(process.getOprno(), process.getLineSn(), sdate, edate);
|
|
|
+ int okCount = Integer.parseInt(dayOks);
|
|
|
+ item.setOkCount(okCount);
|
|
|
+
|
|
|
+ int ngCount = actualCount - okCount;
|
|
|
+ item.setNgCount(ngCount);
|
|
|
+
|
|
|
+ // 设置计划数(和大屏一样的逻辑)
|
|
|
+ Integer planCount = 0;
|
|
|
+ if (plan != null) {
|
|
|
+ try {
|
|
|
+ int oprnoNum = Integer.parseInt(process.getOprno().replaceAll("[^0-9]", ""));
|
|
|
+ if (oprnoNum < 140) {
|
|
|
+ planCount = plan.getP1sx() != null ? plan.getP1sx() : 0;
|
|
|
+ } else {
|
|
|
+ planCount = plan.getP2sx() != null ? plan.getP2sx() : 0;
|
|
|
+ }
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ planCount = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ item.setPlanCount(planCount);
|
|
|
+
|
|
|
+ // 计算达成率
|
|
|
+ if (planCount > 0) {
|
|
|
+ double rate = (actualCount * 100.0) / planCount;
|
|
|
+ item.setAchievementRate(df.format(rate) + "%");
|
|
|
+ } else {
|
|
|
+ item.setAchievementRate("-");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算合格率
|
|
|
+ if (actualCount > 0) {
|
|
|
+ double rate = (okCount * 100.0) / actualCount;
|
|
|
+ item.setQualifiedRate(df.format(rate) + "%");
|
|
|
+ } else {
|
|
|
+ item.setQualifiedRate("-");
|
|
|
+ }
|
|
|
+
|
|
|
+ resultList.add(item);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 下一天
|
|
|
+ startCal.add(Calendar.DAY_OF_MONTH, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ return resultList;
|
|
|
+ }
|
|
|
+}
|