wukai 2 місяців тому
батько
коміт
52c957f406

+ 153 - 10
jjt-biz/src/main/java/com/jjt/dye/controller/DyeTypeProcessController.java

@@ -5,13 +5,18 @@ import com.jjt.common.core.controller.BaseController;
 import com.jjt.common.core.domain.AjaxResult;
 import com.jjt.common.core.page.TableDataInfo;
 import com.jjt.common.enums.BusinessType;
+import com.jjt.common.utils.DateUtils;
+import com.jjt.dye.domain.DyeCalcHour;
 import com.jjt.dye.domain.DyeTypeProcess;
+import com.jjt.dye.service.IDyeCalcHourService;
 import com.jjt.dye.service.IDyeTypeProcessService;
+import com.jjt.dye.vo.DyePowerVO;
 import com.jjt.dye.vo.DyeProcessVO;
 import com.jjt.dye.vo.ProcExpVO;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.web.bind.annotation.*;
 
@@ -25,9 +30,7 @@ import java.net.URLEncoder;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
@@ -43,6 +46,8 @@ import java.util.stream.Collectors;
 public class DyeTypeProcessController extends BaseController {
     @Resource
     private IDyeTypeProcessService dyeTypeProcessService;
+    @Resource
+    private IDyeCalcHourService dyeCalcHourService;
 
     /**
      * 查询染整线设备类型工艺参数列表
@@ -61,8 +66,8 @@ public class DyeTypeProcessController extends BaseController {
      */
     @ApiOperation("导出工艺")
     //@PreAuthorize("@ss.hasPermi('dye:process:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, ProcExpVO vo) {
+    @PostMapping("/exportProc")
+    public void exportProc(HttpServletResponse response, ProcExpVO vo) {
         LocalDate localDate = LocalDate.parse(vo.getDate());
         LocalDateTime localDateTime = LocalDateTime.of(localDate, LocalTime.MIN).plusHours(Integer.parseInt(vo.getHour()));
         List<DyeProcessVO> list = dyeTypeProcessService.searchPara(localDateTime, vo.getTypes(), vo.getLines());
@@ -73,7 +78,7 @@ public class DyeTypeProcessController extends BaseController {
                 String sheetName = line + "#产线";
                 wb.setSheetName(wb.getSheetIndex(sheet), sheetName);
                 Cell title = sheet.getRow(0).getCell(0);
-                title.setCellValue("前整车间生产工艺统计表(" + sheetName + ")" + localDateTime);
+                title.setCellValue("前整车间" + sheetName + "生产工艺统计表(" + DateUtils.parseDateToStr("yyyy-MM-dd HH", DateUtils.toDate(localDateTime)) + ")");
                 AtomicInteger rowNum = new AtomicInteger(3);
                 // 按照sortNum排序
                 vos.stream().sorted(Comparator.comparing(DyeProcessVO::getSortNum)).forEach(d -> {
@@ -86,7 +91,7 @@ public class DyeTypeProcessController extends BaseController {
                                 int startRow = rowNum.get();
 
                                 // 创建15行数据,第一列用设备名称,并且合并单元格,第二列为汉字,第三列为设定值,第四列为实际值
-                                String deviceName = line + "-" + d.getSortNum() + " 定型机";
+                                String deviceName = d.getSortNum() + "#定型机";
 
                                 // 1#循环上风(r/min)
                                 createDataRow(sheet, rowNum.getAndIncrement(), deviceName, "1#循环上风(r/min)",
@@ -163,7 +168,7 @@ public class DyeTypeProcessController extends BaseController {
                             if (highCombingMachineParams != null) {
                                 // 记录起始行号用于合并单元格
                                 int startRow = rowNum.get();
-                                String deviceName = line + "-" + d.getSortNum() + " 高梳机";
+                                String deviceName = "#高梳机";
 
                                 // 大锡林转速(r/min)
                                 createDataRow(sheet, rowNum.getAndIncrement(), deviceName, "大锡林转速(r/min)",
@@ -220,7 +225,7 @@ public class DyeTypeProcessController extends BaseController {
                             if (calenderingMachineParams != null) {
                                 // 记录起始行号用于合并单元格
                                 int startRow = rowNum.get();
-                                String deviceName = line + "-" + d.getSortNum() + " 双棍烫光机";
+                                String deviceName = d.getSortNum() + "#双棍烫光机";
 
                                 // 烫棍1温度(℃)
                                 createDataRow(sheet, rowNum.getAndIncrement(), deviceName, "烫棍1温度(℃)",
@@ -273,7 +278,7 @@ public class DyeTypeProcessController extends BaseController {
                             if (dualBrushMachineParams != null) {
                                 // 记录起始行号用于合并单元格
                                 int startRow = rowNum.get();
-                                String deviceName = line + "-" + d.getSortNum() + " 双棍刷毛机";
+                                String deviceName = "#双棍刷毛机";
 
                                 // 刷辊1隔离(mm)
                                 createDataRow(sheet, rowNum.getAndIncrement(), deviceName, "刷辊1隔离(mm)",
@@ -351,6 +356,144 @@ public class DyeTypeProcessController extends BaseController {
         }
     }
 
+    @ApiOperation("导出工艺")
+    //@PreAuthorize("@ss.hasPermi('dye:process:export')")
+    @PostMapping("/exportPower")
+    public void exportPower(HttpServletResponse response, ProcExpVO vo) {
+        String[] dateRange = vo.getDate().split(",");
+        LocalDate start = LocalDate.parse(dateRange[0]);
+        LocalDate end = LocalDate.parse(dateRange[1]);
+        List<DyePowerVO> list = dyeCalcHourService.searchPower(start, end, vo.getTypes(), vo.getLines());
+        Map<String, List<DyePowerVO>> powerVOsByLine = list.stream().collect(Collectors.groupingBy(DyePowerVO::getLine));
+        try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("tpl/qz-power.xlsx"); XSSFWorkbook wb = new XSSFWorkbook(inputStream); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
+            powerVOsByLine.forEach((line, vos) -> {
+                Sheet sheet = wb.cloneSheet(0);
+                String sheetName = line + "#产线";
+                wb.setSheetName(wb.getSheetIndex(sheet), sheetName);
+
+                // 删除现有的所有合并区域,避免冲突
+                int mergedRegionsCount = sheet.getNumMergedRegions();
+                for (int i = mergedRegionsCount - 1; i >= 0; i--) {
+                    sheet.removeMergedRegion(i);
+                }
+
+                Cell title = sheet.getRow(0).getCell(0);
+                title.setCellValue("前整车间" + sheetName + "生产电量统计表(" + start + "至" + end + ")");
+
+                // 合并标题单元格并设置垂直居中对齐
+                int lastColumnIndex = vos.size() + 1; // 设备列索引从2开始,所以要加1
+                sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, lastColumnIndex));
+
+                // 设置标题单元格垂直居中
+                CellStyle titleStyle = wb.createCellStyle();
+                titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+                titleStyle.setAlignment(HorizontalAlignment.CENTER);
+                title.setCellStyle(titleStyle);
+
+                // 创建带边框的单元格样式
+                CellStyle borderStyle = wb.createCellStyle();
+                borderStyle.setBorderTop(BorderStyle.THIN);
+                borderStyle.setBorderBottom(BorderStyle.THIN);
+                borderStyle.setBorderLeft(BorderStyle.THIN);
+                borderStyle.setBorderRight(BorderStyle.THIN);
+                borderStyle.setAlignment(HorizontalAlignment.CENTER);
+                borderStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+
+                // 按照sortNum排序
+                List<DyePowerVO> sortedVos = vos.stream()
+                        .sorted(Comparator.comparing(DyePowerVO::getSortNum))
+                        .collect(Collectors.toList());
+
+                // 创建设备名称行
+                AtomicInteger index = new AtomicInteger(0);
+                sortedVos.forEach(d -> {
+                    String deviceName = "";
+                    switch (d.getTypeId().intValue()) {
+                        case 2:
+                            deviceName = d.getSortNum() + "#定型机";
+                            break;
+                        case 3:
+                            deviceName = d.getSortNum() + "#高梳机";
+                            break;
+                        case 4:
+                            deviceName = d.getSortNum() + "#双棍烫光机";
+                            break;
+                        case 5:
+                            deviceName = d.getSortNum() + "#双棍刷毛机";
+                            break;
+                        default:
+                            break;
+                    }
+                    Cell deviceNameCell = sheet.getRow(1).createCell(2 + index.getAndIncrement());
+                    deviceNameCell.setCellValue(deviceName);
+                    deviceNameCell.setCellStyle(borderStyle); // 应用边框样式
+                });
+
+                // 收集所有时间点数据
+                Set<String> timePoints = new TreeSet<>();
+                Map<String, Map<Integer, Double>> dataMap = new HashMap<>();
+
+                for (DyePowerVO voItem : sortedVos) {
+                    if (voItem.getPowerList() != null) {
+                        for (DyeCalcHour hour : voItem.getPowerList()) {
+                            // 格式化时间点为 "yyyy-MM-dd,HH"
+                            String timePoint = String.format("%tF,%02d", hour.getDataDate(), hour.getHour());
+                            timePoints.add(timePoint);
+
+                            // 初始化时间点数据
+                            dataMap.putIfAbsent(timePoint, new HashMap<>());
+                            Map<Integer, Double> deviceData = dataMap.get(timePoint);
+                            // 使用sortNum作为设备标识
+                            deviceData.put(voItem.getSortNum(),
+                                    hour.getParaValue() != null ? hour.getParaValue().doubleValue() : 0.0);
+                        }
+                    }
+                }
+
+                // 填充数据到表格
+                int rowIndex = 2;
+                for (String timePoint : timePoints) {
+                    Row row = sheet.createRow(rowIndex++);
+                    String[] dateTimeParts = timePoint.split(",");
+
+                    // 第一列:日期
+                    Cell dateCell = row.createCell(0);
+                    dateCell.setCellValue(dateTimeParts[0]);
+                    dateCell.setCellStyle(borderStyle); // 应用边框样式
+
+                    // 第二列:小时
+                    Cell hourCell = row.createCell(1);
+                    hourCell.setCellValue(dateTimeParts[1]);
+                    hourCell.setCellStyle(borderStyle); // 应用边框样式
+
+                    // 第三列及以后:设备电量数据
+                    Map<Integer, Double> deviceData = dataMap.get(timePoint);
+                    for (int i = 0; i < sortedVos.size(); i++) {
+                        DyePowerVO voItem = sortedVos.get(i);
+                        Cell powerCell = row.createCell(2 + i);
+                        Double powerValue = deviceData.getOrDefault(voItem.getSortNum(), 0.0);
+                        powerCell.setCellValue(powerValue);
+                        powerCell.setCellStyle(borderStyle); // 应用边框样式
+                    }
+                }
+            });
+            wb.removeSheetAt(0);
+            // 清空response
+            response.reset();
+            // 设置response的Header
+            response.setCharacterEncoding("UTF-8");
+            //Content-Disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存
+            //attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3"
+            // filename表示文件的默认名称,因为网络传输只支持URL编码的相关支付,因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
+            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("前整工艺参数.xlsx", "UTF-8"));
+            response.setContentType("application/octet-stream");
+            wb.write(outputStream);
+            outputStream.flush();
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+    }
+
     /**
      * 创建数据行
      *

+ 16 - 1
jjt-biz/src/main/java/com/jjt/dye/service/IDyeCalcHourService.java

@@ -1,6 +1,8 @@
 package com.jjt.dye.service;
 
 import com.jjt.dye.domain.DyeCalcHour;
+import com.jjt.dye.vo.DyePowerVO;
+import com.jjt.dye.vo.DyeProcessVO;
 
 import java.time.LocalDate;
 import java.util.List;
@@ -59,10 +61,12 @@ public interface IDyeCalcHourService {
      * @return 结果
      */
     public int deleteDyeCalcHourByChId(Long chId);
+
     /**
      * 补录数据至当前时间
      */
-     void calc2Curr();
+    void calc2Curr();
+
     /**
      * 计算上一小时数据
      */
@@ -83,4 +87,15 @@ public interface IDyeCalcHourService {
      * @param hour 小时
      */
     List<DyeCalcHour> selectByTime(LocalDate date, int hour);
+
+    /**
+     * 查询指定时间电量数据
+     *
+     * @param start 开始时间
+     * @param end   结束时间
+     * @param types 类型
+     * @param lines 线别
+     * @return 结果
+     */
+    List<DyePowerVO> searchPower(LocalDate start, LocalDate end, String[] types, String[] lines);
 }

+ 46 - 0
jjt-biz/src/main/java/com/jjt/dye/service/impl/DyeCalcHourServiceImpl.java

@@ -3,6 +3,8 @@ package com.jjt.dye.service.impl;
 import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONObject;
 import com.jjt.common.utils.DateUtils;
+import com.jjt.common.utils.StringUtils;
+import com.jjt.common.utils.bean.BeanUtils;
 import com.jjt.dye.domain.DyeCalcHour;
 import com.jjt.dye.domain.DyeDevicePara;
 import com.jjt.dye.domain.DyeTypePara;
@@ -11,6 +13,7 @@ import com.jjt.dye.service.IDyeCalcHourService;
 import com.jjt.dye.service.IDyeDeviceService;
 import com.jjt.dye.service.IDyeHourLineService;
 import com.jjt.dye.vo.DyeDeviceVO;
+import com.jjt.dye.vo.DyePowerVO;
 import com.jjt.utils.IotService;
 import com.jjt.utils.Tools;
 import org.apache.ibatis.session.ExecutorType;
@@ -28,6 +31,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * 小时统计数据Service业务层处理
@@ -185,6 +189,48 @@ public class DyeCalcHourServiceImpl implements IDyeCalcHourService {
     }
 
     /**
+     * 查询指定时间电量数据
+     *
+     * @param start 开始时间
+     * @param end   结束时间
+     * @param types 类型
+     * @param lines 线别
+     * @return 结果
+     */
+    @Override
+    public List<DyePowerVO> searchPower(LocalDate start, LocalDate end, String[] types, String[] lines) {
+        List<DyePowerVO> result = new ArrayList<>();
+        DyeCalcHour search = new DyeCalcHour();
+        Map<String, Object> params = new HashMap<>(16);
+        params.put("start", start.toString());
+        params.put("end", end.toString());
+        search.setParams(params);
+        search.setParaCode("ENG_energy");
+        List<DyeCalcHour> list = selectDyeCalcHourList(search);
+        Map<Long, List<DyeCalcHour>> deviceIdGroup = list.stream().collect(Collectors.groupingBy(DyeCalcHour::getDeviceId));
+        Map<String, List<DyeDeviceVO>> deviceByLine = dyeDeviceService.deviceByLine();
+        for (Map.Entry<String, List<DyeDeviceVO>> entry : deviceByLine.entrySet()) {
+            String line = entry.getKey();
+            if (lines != null && !StringUtils.containsAny(line, lines)) {
+                continue;
+            }
+            List<DyeDeviceVO> devices = entry.getValue();
+            //这个存储iot返回的字段映射  key值为组装的iot返回的name,value为自己组装的s-code-id
+            Map<String, String> fieldMap = new HashMap<>(16);
+            for (DyeDeviceVO device : devices) {
+                if (types != null && !StringUtils.containsAny(device.getTypeId().toString(), types)) {
+                    continue;
+                }
+                DyePowerVO powerVO = new DyePowerVO();
+                BeanUtils.copyProperties(device, powerVO);
+                powerVO.setPowerList(deviceIdGroup.get(device.getDeviceId()));
+                result.add(powerVO);
+            }
+        }
+        return result;
+    }
+
+    /**
      * 通用计算方法
      *
      * @param start         开始时间

+ 41 - 0
jjt-biz/src/main/java/com/jjt/dye/vo/DyePowerVO.java

@@ -0,0 +1,41 @@
+package com.jjt.dye.vo;
+
+import com.jjt.dye.domain.DyeCalcHour;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * DyeDeviceVO$
+ *
+ * @author wukai
+ * @date 2025/11/2 02:33
+ */
+@Data
+public class DyePowerVO {
+    @ApiModelProperty("设备ID")
+    private Long deviceId;
+
+    @ApiModelProperty("类型ID")
+    private Long typeId;
+
+    @ApiModelProperty("车间")
+    private String wsName;
+
+    @ApiModelProperty("产线编号")
+    private String line;
+
+    @ApiModelProperty("类型名称")
+    private String typeName;
+
+    @ApiModelProperty("设备编码")
+    private String deviceCode;
+
+    @ApiModelProperty("设备序号")
+    private Integer sortNum;
+
+    @ApiModelProperty("电量列表")
+    private List<DyeCalcHour> powerList;
+
+}

+ 4 - 1
jjt-biz/src/main/resources/mapper/dye/DyeCalcHourMapper.xml

@@ -7,7 +7,7 @@
     <resultMap type="DyeCalcHour" id="DyeCalcHourResult">
         <result property="chId" column="CH_ID"/>
         <result property="dataDate" column="DATA_DATE"/>
-        <result property="workDay"    column="WORK_DAY"    />
+        <result property="workDay" column="WORK_DAY"/>
         <result property="hour" column="HOUR"/>
         <result property="deviceId" column="DEVICE_ID"/>
         <result property="paraCode" column="PARA_CODE"/>
@@ -42,6 +42,9 @@
             <if test="paraName != null  and paraName != ''">and PARA_NAME like concat('%', #{paraName}, '%')</if>
             <if test="paraValue != null ">and PARA_VALUE = #{paraValue}</if>
             <if test="paraMValue != null  and paraMValue != ''">and PARA_M_VALUE = #{paraMValue}</if>
+            <if test="params.start != null and params.start != '' and params.end != null and params.end != ''">
+                and WORK_DAY between #{params.start} and #{params.end}
+            </if>
         </where>
         order by DATA_DATE, HOUR
     </select>

BIN
jjt-biz/src/main/resources/tpl/qz-power.xlsx