wukai 1 år sedan
förälder
incheckning
e7bdd2107b

+ 155 - 1
ruoyi-admin/src/main/java/com/ruoyi/biz/controller/ApiController.java

@@ -4,6 +4,7 @@ import com.ruoyi.biz.domain.*;
 import com.ruoyi.biz.service.ITwinCalc2hrService;
 import com.ruoyi.biz.service.ITwinCalcDayService;
 import com.ruoyi.biz.service.ITwinDeviceService;
+import com.ruoyi.biz.service.ITwinRecordAlarmsService;
 import com.ruoyi.biz.service.impl.AsyncServiceImpl;
 import com.ruoyi.biz.service.impl.IotTokenServiceImpl;
 import com.ruoyi.common.core.controller.BaseController;
@@ -11,14 +12,28 @@ import com.ruoyi.common.core.domain.R;
 import com.ruoyi.common.utils.DateUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URLEncoder;
 import java.time.LocalDate;
 import java.time.ZoneOffset;
 import java.util.*;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * swagger 用户测试方法
@@ -27,6 +42,7 @@ import java.util.concurrent.Future;
  */
 @Api("数据接口")
 @RestController
+@Slf4j
 @RequestMapping("/api/")
 public class ApiController extends BaseController {
     @Resource
@@ -34,11 +50,16 @@ public class ApiController extends BaseController {
     @Resource
     private ITwinCalc2hrService calc2hrService;
     @Resource
+    private ITwinRecordAlarmsService recordAlarmsService;
+
+    @Resource
     private ITwinDeviceService deviceService;
     @Resource
     private IotTokenServiceImpl iotTokenService;
     @Resource
     private AsyncServiceImpl asyncService;
+    @Value("${excel.template}")
+    private String excelTemplate;
 
     @ApiOperation("首页统计数据")
     @GetMapping("/index")
@@ -187,5 +208,138 @@ public class ApiController extends BaseController {
         }
         return R.ok(result);
     }
+
+    @ApiOperation("设备具体数据")
+    @GetMapping("/export")
+    @CrossOrigin(origins = "*")
+    public void export(Date start, Date end, HttpServletResponse response) {
+        if (start == null) {
+            LocalDate localDate = LocalDate.now().minusDays(7);
+            start = Date.from(localDate.atStartOfDay(ZoneOffset.of("+8")).toInstant());
+        }
+        List<TwinCalc2hr> list = calc2hrService.calc2hrList(start, end);
+        Map<String, Object> queryMap = new HashMap<>(16);
+        queryMap.put("start", start);
+        queryMap.put("end", end);
+        TwinRecordAlarms recordAlarms = new TwinRecordAlarms();
+        recordAlarms.setAlarmType("stop");
+        recordAlarms.setParams(queryMap);
+        List<TwinRecordAlarms> alarms = recordAlarmsService.selectTwinRecordAlarmsList(recordAlarms);
+        // path是指想要下载的文件的路径
+        // 读取现有的xlsx文件
+        try (FileInputStream inputStream = new FileInputStream(excelTemplate); Workbook wb = new XSSFWorkbook(inputStream); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
+            Sheet sheet = wb.getSheetAt(0);
+            AtomicInteger rowNum = new AtomicInteger(2);
+            //填充数据
+            list.forEach(calc2hr -> {
+                Row row = sheet.createRow(rowNum.get());
+                Cell[] cells = new Cell[25];
+                for (int i = 0; i < cells.length; i++) {
+                    cells[i] = row.createCell(i);
+                }
+                //设备名称
+                cells[0].setCellValue(calc2hr.getRemark());
+                //时间
+                cells[1].setCellValue(DateUtils.parseDateToStr(calc2hr.getDataDate()));
+                //总长
+                cells[2].setCellValue(calc2hr.getLengthA().add(calc2hr.getLengthB()).floatValue());
+                //总重
+                cells[3].setCellValue(calc2hr.getWeightA().add(calc2hr.getWeightB()).floatValue());
+                //稼动率 TODO 暂时无数据
+                cells[4].setCellValue("");
+                // 总电量 TODO 暂时无数据
+                cells[5].setCellValue("");
+                //告警次数
+                cells[6].setCellValue(calc2hr.getAlarm());
+                //A班米长
+                cells[7].setCellValue(calc2hr.getLengthA().floatValue());
+                //A班重量
+                cells[8].setCellValue(calc2hr.getWeightA().floatValue());
+                //A班开机时间
+                cells[9].setCellValue(calc2hr.getOpenTimeA().floatValue());
+                //A班停机时间
+                cells[10].setCellValue(calc2hr.getCloseTimeA().floatValue());
+                //A班稼动率 TODO 暂时无数据
+                cells[11].setCellValue("");
+                //A班电量 TODO 暂时无数据
+                cells[12].setCellValue("");
+                //A班停经片停机次数
+                cells[13].setCellValue(calc2hr.getStop1A());
+                //A班CCD停机次数
+                cells[14].setCellValue(calc2hr.getStop2A());
+                //A班人工停机次数
+                cells[15].setCellValue(calc2hr.getStop3A());
+                //B班米长
+                cells[16].setCellValue(calc2hr.getLengthB().floatValue());
+                //B班重量
+                cells[17].setCellValue(calc2hr.getWeightB().floatValue());
+                //B班开机时间
+                cells[18].setCellValue(calc2hr.getOpenTimeB().floatValue());
+                //B班停机时间
+                cells[19].setCellValue(calc2hr.getCloseTimeB().floatValue());
+                //B班稼动率 TODO 暂时无数据
+                cells[20].setCellValue("");
+                //B班电量 TODO 暂时无数据
+                cells[21].setCellValue("");
+                //B班停经片停机次数
+                cells[22].setCellValue(calc2hr.getStop1B());
+                //B班CCD停机次数
+                cells[23].setCellValue(calc2hr.getStop2B());
+                //B班人工停机次数
+                cells[24].setCellValue(calc2hr.getStop3B());
+                rowNum.getAndIncrement();
+            });
+
+            AtomicInteger row1num = new AtomicInteger(1);
+            Sheet sheet1 = wb.getSheetAt(1);
+            //填充数据
+            alarms.forEach(alarm -> {
+                Row row = sheet1.createRow(row1num.get());
+                Cell cell = row.createCell(0);
+                cell.setCellValue(alarm.getRemark());
+                cell = row.createCell(1);
+                cell.setCellValue(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, alarm.getDataTime()));
+                cell = row.createCell(2);
+                switch (alarm.getAlarmCode().intValue()) {
+                    case 1:
+                        cell.setCellValue("停经片停机");
+                        break;
+                    case 2:
+                        cell.setCellValue("CCD停机");
+                        break;
+                    case 3:
+                        cell.setCellValue("人工停机");
+                        break;
+                    case 4:
+                        cell.setCellValue("断电停机");
+                        break;
+                    case 5:
+                        cell.setCellValue("设备故障停机");
+                        break;
+                    case 6:
+                        cell.setCellValue("落布米数达到停机");
+                        break;
+                    case 7:
+                        cell.setCellValue("盘头剩余圈数达到停机");
+                        break;
+                    default:
+                }
+                row1num.getAndIncrement();
+            });
+
+            // 清空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("数据导出" + System.currentTimeMillis() + ".xlsx", "UTF-8"));
+            response.setContentType("application/octet-stream");
+            wb.write(outputStream);
+            outputStream.flush();
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+    }
 }
-;

+ 8 - 0
ruoyi-admin/src/main/java/com/ruoyi/biz/mapper/TwinCalc2hrMapper.java

@@ -89,4 +89,12 @@ public interface TwinCalc2hrMapper {
      * @return 列表
      */
     List<TwinCalc2hr> selectTwinCalc2hrListByTime(@Param("date")Date date, @Param("id")Long id);
+    /**
+     * 按设备分类统计日数据
+     *
+     * @param start 开始时间
+     * @param end   结束时间
+     * @return 列表
+     */
+    List<TwinCalc2hr> calc2hrList(@Param("start")Date start, @Param("end")Date end);
 }

+ 10 - 1
ruoyi-admin/src/main/java/com/ruoyi/biz/service/ITwinCalc2hrService.java

@@ -92,9 +92,18 @@ public interface ITwinCalc2hrService {
      */
     List<TwinCalc2hr> selectTwinCalc2hrListByTime(Date date, Long id);
     /**
+     * 按设备分类统计日数据
+     *
+     * @param start 开始时间
+     * @param end   结束时间
+     * @return 列表
+     */
+    List<TwinCalc2hr> calc2hrList(Date start, Date end);
+
+    /**
      * 查询指定设备的周统计数据
      *
-     * @param twinDevice 设备对象
+     * @param info 设备对象
      * @return 列表
      */
     List<TwinCalc2hr> selectWeekData(TwinDevice info);

+ 13 - 1
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/TwinCalc2hrServiceImpl.java

@@ -138,7 +138,7 @@ public class TwinCalc2hrServiceImpl implements ITwinCalc2hrService {
     }
 
     /**
-     * 查询指定时间之后的日统计数据
+     * 根据设备ID查询指定时间之后的日统计数据
      *
      * @param date 指定时间
      * @param id   设备ID
@@ -150,6 +150,18 @@ public class TwinCalc2hrServiceImpl implements ITwinCalc2hrService {
     }
 
     /**
+     * 按设备分类统计日数据
+     *
+     * @param start 开始时间
+     * @param end   结束时间
+     * @return 列表
+     */
+    @Override
+    public List<TwinCalc2hr> calc2hrList(Date start, Date end) {
+        return twinCalc2hrMapper.calc2hrList(start, end);
+    }
+
+    /**
      * 查询指定设备的周统计数据
      *
      * @param twinDevice 设备对象

+ 2 - 1
ruoyi-admin/src/main/resources/application.yml

@@ -6,7 +6,8 @@ iot:
   username: supplier
   password: 123456
   authorization: Basic c2FiZXI6c2FiZXJfc2VjcmV0
-
+excel:
+  template: D:\SYSTEM\Desktop\temp\excel\template.xlsx
 # 项目相关配置
 ruoyi:
   # 名称

+ 41 - 16
ruoyi-admin/src/main/resources/mapper/biz/TwinCalc2hrMapper.xml

@@ -145,22 +145,22 @@
     </select>
     <select id="selectTwinCalc2hrListByTime" resultMap="TwinCalc2hrResult">
         SELECT DATA_DATE,
-               MAX(CONVERT(TIME_PERIOD, UNSIGNED))  TIME_PERIOD,
-               SUM(LENGTH_A)     LENGTH_A,
-               SUM(OPEN_TIME_A)  OPEN_TIME_A,
-               SUM(CLOSE_TIME_A) CLOSE_TIME_A,
-               SUM(LENGTH_B)     LENGTH_B,
-               SUM(CLOSE_TIME_B) CLOSE_TIME_B,
-               SUM(OPEN_TIME_B)  OPEN_TIME_B,
-               SUM(WEIGHT_A)     WEIGHT_A,
-               SUM(WEIGHT_B)     WEIGHT_B,
-               SUM(ALARM)        ALARM,
-               SUM(STOP1_A)      STOP1_A,
-               SUM(STOP2_A)      STOP2_A,
-               SUM(STOP3_A)      STOP3_A,
-               SUM(STOP1_B)      STOP1_B,
-               SUM(STOP2_B)      STOP2_B,
-               SUM(STOP3_B)      STOP3_B
+               MAX(CONVERT(TIME_PERIOD, UNSIGNED)) TIME_PERIOD,
+               SUM(LENGTH_A)                       LENGTH_A,
+               SUM(OPEN_TIME_A)                    OPEN_TIME_A,
+               SUM(CLOSE_TIME_A)                   CLOSE_TIME_A,
+               SUM(LENGTH_B)                       LENGTH_B,
+               SUM(CLOSE_TIME_B)                   CLOSE_TIME_B,
+               SUM(OPEN_TIME_B)                    OPEN_TIME_B,
+               SUM(WEIGHT_A)                       WEIGHT_A,
+               SUM(WEIGHT_B)                       WEIGHT_B,
+               SUM(ALARM)                          ALARM,
+               SUM(STOP1_A)                        STOP1_A,
+               SUM(STOP2_A)                        STOP2_A,
+               SUM(STOP3_A)                        STOP3_A,
+               SUM(STOP1_B)                        STOP1_B,
+               SUM(STOP2_B)                        STOP2_B,
+               SUM(STOP3_B)                        STOP3_B
         FROM TWIN_CALC_2HR
         WHERE DATA_DATE >= #{date}
           AND DEVICE_ID = #{id}
@@ -253,6 +253,31 @@
         </trim>
         where ID = #{id}
     </update>
+    <select id="calc2hrList" resultMap="TwinCalc2hrResult">
+        select a.device_name remark,b.* from twin_device a,(
+        SELECT DATA_DATE,
+        DEVICE_ID,
+        SUM(LENGTH_A) LENGTH_A,
+        SUM(OPEN_TIME_A) OPEN_TIME_A,
+        SUM(CLOSE_TIME_A) CLOSE_TIME_A,
+        SUM(LENGTH_B) LENGTH_B,
+        SUM(CLOSE_TIME_B) CLOSE_TIME_B,
+        SUM(OPEN_TIME_B) OPEN_TIME_B,
+        SUM(WEIGHT_A) WEIGHT_A,
+        SUM(WEIGHT_B) WEIGHT_B,
+        SUM(ALARM) ALARM,
+        SUM(STOP1_A) STOP1_A,
+        SUM(STOP2_A) STOP2_A,
+        SUM(STOP3_A) STOP3_A,
+        SUM(STOP1_B) STOP1_B,
+        SUM(STOP2_B) STOP2_B,
+        SUM(STOP3_B) STOP3_B
+        FROM TWIN_CALC_2HR
+        WHERE DATA_DATE >= #{start}
+        <if test="end != null ">and DATA_DATE &lt;= #{end}</if>
+        GROUP BY DATA_DATE,DEVICE_ID
+        ) B WHERE A.ID=B.DEVICE_ID ORDER BY DEVICE_ID,DATA_DATE
+    </select>
 
     <delete id="deleteTwinCalc2hrById" parameterType="Long">
         delete

+ 60 - 32
ruoyi-admin/src/main/resources/mapper/biz/TwinRecordAlarmsMapper.xml

@@ -1,46 +1,72 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE mapper
-PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ruoyi.biz.mapper.TwinRecordAlarmsMapper">
-    
+
     <resultMap type="TwinRecordAlarms" id="TwinRecordAlarmsResult">
-        <result property="id"    column="ID"    />
-        <result property="deviceId"    column="DEVICE_ID"    />
-        <result property="dataTime"    column="DATA_TIME"    />
-        <result property="alarmType"    column="ALARM_TYPE"    />
-        <result property="alarmCode"    column="ALARM_CODE"    />
-        <result property="createdBy"    column="CREATED_BY"    />
-        <result property="createdTime"    column="CREATED_TIME"    />
-        <result property="updatedBy"    column="UPDATED_BY"    />
-        <result property="updatedTime"    column="UPDATED_TIME"    />
-        <result property="remark"    column="REMARK"    />
+        <result property="id" column="ID"/>
+        <result property="deviceId" column="DEVICE_ID"/>
+        <result property="dataTime" column="DATA_TIME"/>
+        <result property="alarmType" column="ALARM_TYPE"/>
+        <result property="alarmCode" column="ALARM_CODE"/>
+        <result property="createdBy" column="CREATED_BY"/>
+        <result property="createdTime" column="CREATED_TIME"/>
+        <result property="updatedBy" column="UPDATED_BY"/>
+        <result property="updatedTime" column="UPDATED_TIME"/>
+        <result property="remark" column="REMARK"/>
     </resultMap>
 
     <sql id="selectTwinRecordAlarmsVo">
-        select ID, DEVICE_ID, DATA_TIME, ALARM_TYPE, ALARM_CODE, CREATED_BY, CREATED_TIME, UPDATED_BY, UPDATED_TIME, REMARK from twin_record_alarms
+        select ID,
+               DEVICE_ID,
+               DATA_TIME,
+               ALARM_TYPE,
+               ALARM_CODE,
+               CREATED_BY,
+               CREATED_TIME,
+               UPDATED_BY,
+               UPDATED_TIME,
+               REMARK
+        from twin_record_alarms
     </sql>
 
     <select id="selectTwinRecordAlarmsList" parameterType="TwinRecordAlarms" resultMap="TwinRecordAlarmsResult">
-        <include refid="selectTwinRecordAlarmsVo"/>
-        <where>  
-            <if test="deviceId != null "> and DEVICE_ID = #{deviceId}</if>
-            <if test="dataTime != null "> and DATA_TIME = #{dataTime}</if>
-            <if test="alarmType != null  and alarmType != ''"> and ALARM_TYPE = #{alarmType}</if>
-            <if test="alarmCode != null "> and ALARM_CODE = #{alarmCode}</if>
-            <if test="createdBy != null  and createdBy != ''"> and CREATED_BY = #{createdBy}</if>
-            <if test="createdTime != null "> and CREATED_TIME = #{createdTime}</if>
-            <if test="updatedBy != null  and updatedBy != ''"> and UPDATED_BY = #{updatedBy}</if>
-            <if test="updatedTime != null "> and UPDATED_TIME = #{updatedTime}</if>
-            <if test="remark != null  and remark != ''"> and REMARK = #{remark}</if>
+        select a.device_name remark,b.* from twin_device a,( select ID,
+        DEVICE_ID,
+        DATA_TIME,
+        ALARM_TYPE,
+        ALARM_CODE,
+        CREATED_BY,
+        CREATED_TIME,
+        UPDATED_BY,
+        UPDATED_TIME
+        from twin_record_alarms
+        <where>
+            <if test="deviceId != null ">and DEVICE_ID = #{deviceId}</if>
+            <if test="dataTime != null ">and DATA_TIME = #{dataTime}</if>
+            <if test="alarmType != null  and alarmType != ''">and ALARM_TYPE = #{alarmType}</if>
+            <if test="alarmCode != null ">and ALARM_CODE = #{alarmCode}</if>
+            <if test="createdBy != null  and createdBy != ''">and CREATED_BY = #{createdBy}</if>
+            <if test="createdTime != null ">and CREATED_TIME = #{createdTime}</if>
+            <if test="updatedBy != null  and updatedBy != ''">and UPDATED_BY = #{updatedBy}</if>
+            <if test="updatedTime != null ">and UPDATED_TIME = #{updatedTime}</if>
+            <if test="remark != null  and remark != ''">and REMARK = #{remark}</if>
+            <if test="params.start != null"><!-- 开始时间检索 -->
+                and DATA_TIME &gt;= #{params.start}
+            </if>
+            <if test="params.end != null"><!-- 结束时间检索 -->
+                and DATA_TIME &lt;= #{params.end}
+            </if>
         </where>
+        )b WHERE A.ID=B.DEVICE_ID ORDER BY DEVICE_ID,DATA_TIME
     </select>
-    
+
     <select id="selectTwinRecordAlarmsById" parameterType="Long" resultMap="TwinRecordAlarmsResult">
         <include refid="selectTwinRecordAlarmsVo"/>
         where ID = #{id}
     </select>
-        
+
     <insert id="insertTwinRecordAlarms" parameterType="TwinRecordAlarms" useGeneratedKeys="true" keyProperty="id">
         insert into twin_record_alarms
         <trim prefix="(" suffix=")" suffixOverrides=",">
@@ -53,7 +79,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="updatedBy != null">UPDATED_BY,</if>
             <if test="updatedTime != null">UPDATED_TIME,</if>
             <if test="remark != null">REMARK,</if>
-         </trim>
+        </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="deviceId != null">#{deviceId},</if>
             <if test="dataTime != null">#{dataTime},</if>
@@ -64,7 +90,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="updatedBy != null">#{updatedBy},</if>
             <if test="updatedTime != null">#{updatedTime},</if>
             <if test="remark != null">#{remark},</if>
-         </trim>
+        </trim>
     </insert>
 
     <update id="updateTwinRecordAlarms" parameterType="TwinRecordAlarms">
@@ -84,14 +110,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </update>
 
     <delete id="deleteTwinRecordAlarmsById" parameterType="Long">
-        delete from twin_record_alarms where ID = #{id}
+        delete
+        from twin_record_alarms
+        where ID = #{id}
     </delete>
 
     <delete id="deleteTwinRecordAlarmsByIds" parameterType="String">
-        delete from twin_record_alarms where ID in 
+        delete from twin_record_alarms where ID in
         <foreach item="id" collection="array" open="(" separator="," close=")">
             #{id}
         </foreach>
     </delete>
 
-</mapper>
+</mapper>

+ 131 - 0
ruoyi-admin/src/test/java/com/jjt/excel/ExcelExportExample.java

@@ -0,0 +1,131 @@
+package com.jjt.excel;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class ExcelExportExample {
+    public static void main(String[] args) throws Exception {
+        String template = "D:\\SYSTEM\\Desktop\\temp\\excel\\template.xlsx";
+        // 读取现有的xlsx文件
+        FileInputStream inputStream = new FileInputStream(template);
+        Workbook wb = new XSSFWorkbook(inputStream);
+        Sheet sheet = wb.getSheetAt(0);
+        // 填充数据
+        for (int i = 2; i <= 10; i++) {
+            Row row = sheet.createRow(i);
+            Cell cell = row.createCell(0);
+            cell.setCellValue(i);
+            cell = row.createCell(1);
+            cell.setCellValue("Name " + i);
+            cell = row.createCell(2);
+            cell.setCellValue(20 + i);
+        }
+
+        try (FileOutputStream outputStream = new FileOutputStream("D:\\SYSTEM\\Desktop\\temp\\excel\\test.xlsx")) {
+            wb.write(outputStream);
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                wb.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+//        exportExcel();
+    }
+
+    public static void exportExcel() {
+        Workbook workbook = new XSSFWorkbook();
+        Sheet sheet = workbook.createSheet("统计数据");
+
+        // 创建标题行,2行
+        Row titleRow1 = sheet.createRow(0);
+        Cell titleCell = titleRow1.createCell(0);
+        titleCell.setCellValue("设备名");
+        titleCell = titleRow1.createCell(1);
+        titleCell.setCellValue("时间");
+        titleCell = titleRow1.createCell(2);
+        titleCell.setCellValue("总米长");
+        titleCell = titleRow1.createCell(3);
+        titleCell.setCellValue("总重量");
+        titleCell = titleRow1.createCell(4);
+        titleCell.setCellValue("告警次数");
+        titleCell = titleRow1.createCell(5);
+        titleCell.setCellValue("A班");
+        titleCell = titleRow1.createCell(12);
+        titleCell.setCellValue("B班");
+        Row titleRow2 = sheet.createRow(1);
+        titleCell = titleRow2.createCell(5);
+        titleCell.setCellValue("米长");
+        titleCell = titleRow2.createCell(12);
+        titleCell.setCellValue("米长");
+        titleCell = titleRow2.createCell(6);
+        titleCell.setCellValue("重量");
+        titleCell = titleRow2.createCell(13);
+        titleCell.setCellValue("重量");
+        titleCell = titleRow2.createCell(7);
+        titleCell.setCellValue("开机\n时间");
+        titleCell = titleRow2.createCell(14);
+        titleCell.setCellValue("开机\n时间");
+        titleCell = titleRow2.createCell(8);
+        titleCell.setCellValue("停机\n时间");
+        titleCell = titleRow2.createCell(15);
+        titleCell.setCellValue("停机\n时间");
+        titleCell = titleRow2.createCell(9);
+        titleCell.setCellValue("停经片\n停机次数");
+        titleCell = titleRow2.createCell(16);
+        titleCell.setCellValue("停经片\n停机次数");
+        titleCell = titleRow2.createCell(10);
+        titleCell.setCellValue("CCD\n停机次数");
+        titleCell = titleRow2.createCell(17);
+        titleCell.setCellValue("CCD\n停机次数");
+        titleCell = titleRow2.createCell(11);
+        titleCell.setCellValue("人工\n停机次数");
+        titleCell = titleRow2.createCell(18);
+        titleCell.setCellValue("人工\n停机次数");
+
+        sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 0));
+        sheet.addMergedRegion(new CellRangeAddress(0, 1, 1, 1));
+        sheet.addMergedRegion(new CellRangeAddress(0, 1, 2, 2));
+        sheet.addMergedRegion(new CellRangeAddress(0, 1, 3, 3));
+        sheet.addMergedRegion(new CellRangeAddress(0, 1, 4, 4));
+        sheet.addMergedRegion(new CellRangeAddress(0, 0, 5, 11));
+        sheet.addMergedRegion(new CellRangeAddress(0, 0, 12, 18));
+
+        //设置自适应宽度
+        for (int i = 0; i <= 18; i++) {
+            sheet.autoSizeColumn(i, true);
+        }
+        // 填充数据
+        for (int i = 2; i <= 10; i++) {
+            Row row = sheet.createRow(i);
+            Cell cell = row.createCell(0);
+            cell.setCellValue(i);
+            cell = row.createCell(1);
+            cell.setCellValue("Name " + i);
+            cell = row.createCell(2);
+            cell.setCellValue(20 + i);
+        }
+
+        try (FileOutputStream outputStream = new FileOutputStream("example.xlsx")) {
+            workbook.write(outputStream);
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                workbook.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}