Selaa lähdekoodia

分时用电接口开发完成:支路列表、电量趋势、表格统计、导出

fuyuchuan 18 tuntia sitten
vanhempi
commit
1013c3136c
21 muutettua tiedostoa jossa 1132 lisäystä ja 96 poistoa
  1. 19 2
      fiveep-controller/src/main/java/com/bizmatics/controller/web/DeviceController.java
  2. 32 8
      fiveep-controller/src/main/java/com/bizmatics/controller/web/HtAnalogDataController.java
  3. 25 0
      fiveep-controller/src/main/java/com/bizmatics/controller/web/StarMarkingEquipmentController.java
  4. 2 2
      fiveep-controller/src/main/resources/application-dev.properties
  5. 6 4
      fiveep-controller/src/main/resources/application-prod.properties
  6. 3 0
      fiveep-model/src/main/java/com/bizmatics/model/DeviceList.java
  7. 30 1
      fiveep-model/src/main/java/com/bizmatics/model/SiteElectricityRecord.java
  8. 4 1
      fiveep-persistence/src/main/java/com/bizmatics/persistence/mapper/DeviceMapper.java
  9. 41 10
      fiveep-persistence/src/main/resources/mapper/mysql/DeviceMapper.xml
  10. 16 0
      fiveep-service/pom.xml
  11. 4 2
      fiveep-service/src/main/java/com/bizmatics/service/DeviceService.java
  12. 27 4
      fiveep-service/src/main/java/com/bizmatics/service/HtAnalogDataService.java
  13. 40 39
      fiveep-service/src/main/java/com/bizmatics/service/impl/DeviceServiceImpl.java
  14. 596 3
      fiveep-service/src/main/java/com/bizmatics/service/impl/HtAnalogDataServiceImpl.java
  15. 45 19
      fiveep-service/src/main/java/com/bizmatics/service/job/SiteDailyElectricityCostTask.java
  16. 44 0
      fiveep-service/src/main/java/com/bizmatics/service/vo/ElectricityTrendRequestVO.java
  17. 27 0
      fiveep-service/src/main/java/com/bizmatics/service/vo/ElectricityTrendResponseVO.java
  18. 41 0
      fiveep-service/src/main/java/com/bizmatics/service/vo/ElectricityTrendVO.java
  19. 53 0
      fiveep-service/src/main/java/com/bizmatics/service/vo/TimeSharingElectricityRequestVO.java
  20. 76 0
      fiveep-service/src/main/java/com/bizmatics/service/vo/TimeSharingElectricityResponseVO.java
  21. 1 1
      pom.xml

+ 19 - 2
fiveep-controller/src/main/java/com/bizmatics/controller/web/DeviceController.java

@@ -68,6 +68,23 @@ public class DeviceController {
         return ApiResult.success(deviceService.deviceList(siteId));
         return ApiResult.success(deviceService.deviceList(siteId));
     }
     }
 
 
+    /**
+     * 分时用电-设备分页列表查询
+     *
+     * @param siteId     站点ID
+     * @param deviceType 设备类型 默认1、支路设备(183 用电设备), 2、分路设备(171、173用电设备)
+     * @param pageNum    页数
+     * @param pageSize   条数
+     * @return
+     */
+    @GetMapping("list")
+    public ApiResult<List<DeviceList>> branch(@RequestParam(value = "siteId") int siteId,
+                                              @RequestParam(value = "deviceType", required = false, defaultValue = "1") int deviceType,
+                                              @RequestParam(value = "pageNum", required = false, defaultValue = "1") int pageNum,
+                                              @RequestParam(value = "pageSize", required = false, defaultValue = "20") int pageSize) {
+        return ApiResult.success(deviceService.deviceBranch(siteId, deviceType, pageNum, pageSize));
+    }
+
 
 
     /**
     /**
      * 数据管理-同比分析报表-右侧设备查询
      * 数据管理-同比分析报表-右侧设备查询
@@ -242,7 +259,7 @@ public class DeviceController {
      */
      */
     @Log(title = "设备管理-通信设备", businessType = BusinessType.IMPORT)
     @Log(title = "设备管理-通信设备", businessType = BusinessType.IMPORT)
     @PostMapping("/deviceImport")
     @PostMapping("/deviceImport")
-    public ApiResult<Void> deviceImport(@RequestParam("file") MultipartFile file){
+    public ApiResult<Void> deviceImport(@RequestParam("file") MultipartFile file) {
         deviceService.deviceImport(file);
         deviceService.deviceImport(file);
         return ApiResult.success();
         return ApiResult.success();
     }
     }
@@ -253,7 +270,7 @@ public class DeviceController {
      * @return
      * @return
      */
      */
     @GetMapping("deviceBoxList")
     @GetMapping("deviceBoxList")
-    public ApiResult<List<DeviceOneVo>> deviceBoxList(@RequestParam (required = false) Integer siteId) {
+    public ApiResult<List<DeviceOneVo>> deviceBoxList(@RequestParam(required = false) Integer siteId) {
         return ApiResult.success(deviceService.deviceBoxList(siteId));
         return ApiResult.success(deviceService.deviceBoxList(siteId));
     }
     }
 
 

+ 32 - 8
fiveep-controller/src/main/java/com/bizmatics/controller/web/HtAnalogDataController.java

@@ -1,7 +1,7 @@
 package com.bizmatics.controller.web;
 package com.bizmatics.controller.web;
 
 
-
 import com.bizmatics.common.core.bean.ApiResult;
 import com.bizmatics.common.core.bean.ApiResult;
+import com.bizmatics.common.core.bean.CommonPage;
 import com.bizmatics.model.vo.DataManagementOneVO;
 import com.bizmatics.model.vo.DataManagementOneVO;
 import com.bizmatics.model.vo.HtAnalogEnergyConsumptionVo;
 import com.bizmatics.model.vo.HtAnalogEnergyConsumptionVo;
 import com.bizmatics.model.vo.HtAnalogEnergySegmentedVo;
 import com.bizmatics.model.vo.HtAnalogEnergySegmentedVo;
@@ -9,19 +9,16 @@ import com.bizmatics.model.vo.SingleLoopReportOneVo;
 import com.bizmatics.service.HtAnalogDataService;
 import com.bizmatics.service.HtAnalogDataService;
 import com.bizmatics.service.aop.BusinessType;
 import com.bizmatics.service.aop.BusinessType;
 import com.bizmatics.service.aop.Log;
 import com.bizmatics.service.aop.Log;
-import com.bizmatics.service.vo.CommonIcoVO;
-import com.bizmatics.service.vo.HadCountVO;
-import com.bizmatics.service.vo.RealScoreVO;
-import com.bizmatics.service.vo.TimeShareVO;
+import com.bizmatics.service.vo.*;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.format.annotation.DateTimeFormat;
 import org.springframework.format.annotation.DateTimeFormat;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
-import java.time.LocalDate;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URLEncoder;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoUnit;
 import java.util.Date;
 import java.util.Date;
 import java.util.List;
 import java.util.List;
 
 
@@ -259,5 +256,32 @@ public class HtAnalogDataController {
         }
         }
         return ApiResult.success(htAnalogDataService.getSegmentedData(siteId, queryPeriod, queryTime, queryType));
         return ApiResult.success(htAnalogDataService.getSegmentedData(siteId, queryPeriod, queryTime, queryType));
     }
     }
+
+    /**
+     * 时间分时电量、电费-表格统计
+     * @param request 请求参数
+     * @return 响应
+     */
+    @PostMapping("page")
+    public ApiResult<CommonPage<TimeSharingElectricityResponseVO>> timeSharingElectricity(@RequestBody TimeSharingElectricityRequestVO request) {
+        return ApiResult.success(htAnalogDataService.timeSharingElectricity(request));
+    }
+
+    /**
+     * 分时用电-电量趋势
+     * @param trendVO 请求参数
+     * @return 响应
+     */
+    @PostMapping("trend")
+    public ApiResult<List<ElectricityTrendResponseVO>> trend(@RequestBody ElectricityTrendRequestVO trendVO) {
+        return ApiResult.success(htAnalogDataService.trend(trendVO));
+    }
+
+    @PostMapping("export")
+    public void export(@RequestBody TimeSharingElectricityRequestVO request, HttpServletResponse response) throws IOException {
+        htAnalogDataService.export(request, response);
+
+    }
+
 }
 }
 
 

+ 25 - 0
fiveep-controller/src/main/java/com/bizmatics/controller/web/StarMarkingEquipmentController.java

@@ -0,0 +1,25 @@
+package com.bizmatics.controller.web;
+
+import com.bizmatics.persistence.mapper.HtAnalogDataMapper;
+import com.bizmatics.service.HtAnalogDataService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/9/4
+ */
+@RestController
+@RequestMapping("/starMarkingEquipment")
+public class StarMarkingEquipmentController {
+    @Autowired
+    private HtAnalogDataService htAnalogDataService;
+    @Autowired
+    private HtAnalogDataMapper htAnalogDataMapper;
+
+    // @RequestMapping("/powerLevel")
+    // public
+}

+ 2 - 2
fiveep-controller/src/main/resources/application-dev.properties

@@ -19,10 +19,10 @@ spring.autoconfigure.exclude=com.alibaba.druid.spring.boot.autoconfigure.DruidDa
 spring.datasource.dynamic.primary=usky-power
 spring.datasource.dynamic.primary=usky-power
 #spring.datasource.dynamic.datasource.usky-power.url=jdbc:mysql://usky-cloud-mysql:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
 #spring.datasource.dynamic.datasource.usky-power.url=jdbc:mysql://usky-cloud-mysql:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
 #spring.datasource.dynamic.datasource.usky-power.url=jdbc:mysql://dianli.usky.cn:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
 #spring.datasource.dynamic.datasource.usky-power.url=jdbc:mysql://dianli.usky.cn:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
-#spring.datasource.dynamic.datasource.usky-power.url=jdbc:mysql://101.133.214.75:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
+spring.datasource.dynamic.datasource.usky-power.url=jdbc:mysql://101.133.214.75:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
 spring.datasource.dynamic.datasource.usky-power.username=usky
 spring.datasource.dynamic.datasource.usky-power.username=usky
 spring.datasource.dynamic.datasource.usky-power.password=Yt#75Usky
 spring.datasource.dynamic.datasource.usky-power.password=Yt#75Usky
-spring.datasource.dynamic.druid.initial-size=5                                                                       
+spring.datasource.dynamic.druid.initial-size=5
 spring.datasource.dynamic.druid.min-idle=5
 spring.datasource.dynamic.druid.min-idle=5
 spring.datasource.dynamic.druid.max-active=30
 spring.datasource.dynamic.druid.max-active=30
 spring.datasource.dynamic.druid.max-wait=60000
 spring.datasource.dynamic.druid.max-wait=60000

+ 6 - 4
fiveep-controller/src/main/resources/application-prod.properties

@@ -14,14 +14,16 @@ mybatis-plus.configuration.defaultStatementTimeout=3
 mybatis.refresh.enabled=true
 mybatis.refresh.enabled=true
 mybatis.refresh.delay-seconds=10
 mybatis.refresh.delay-seconds=10
 mybatis.refresh.sleep-seconds=20
 mybatis.refresh.sleep-seconds=20
+# SQL日志打印
+mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
 # datasource
 # datasource
 spring.autoconfigure.exclude=com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
 spring.autoconfigure.exclude=com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
 spring.datasource.dynamic.primary=usky-power
 spring.datasource.dynamic.primary=usky-power
 #spring.datasource.dynamic.datasource.usky-power.url=jdbc:mysql://usky-cloud-mysql:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
 #spring.datasource.dynamic.datasource.usky-power.url=jdbc:mysql://usky-cloud-mysql:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
 #spring.datasource.dynamic.datasource.usky-power.url=jdbc:mysql://101.133.214.75:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
 #spring.datasource.dynamic.datasource.usky-power.url=jdbc:mysql://101.133.214.75:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
-spring.datasource.dynamic.datasource.mast.url=jdbc:mysql://101.133.214.75:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
-spring.datasource.dynamic.datasource.mast.username=usky
-spring.datasource.dynamic.datasource.mast.password=Yt#75Usky
+spring.datasource.dynamic.datasource.usky-power.url=jdbc:mysql://101.133.214.75:3306/usky-electricity?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
+spring.datasource.dynamic.datasource.usky-power.username=usky
+spring.datasource.dynamic.datasource.usky-power.password=Yt#75Usky
 spring.datasource.dynamic.druid.initial-size=5
 spring.datasource.dynamic.druid.initial-size=5
 spring.datasource.dynamic.druid.min-idle=5
 spring.datasource.dynamic.druid.min-idle=5
 spring.datasource.dynamic.druid.max-active=30
 spring.datasource.dynamic.druid.max-active=30
@@ -74,7 +76,7 @@ spring.cache.ehcache.config=classpath:ehcache.xml
 # redis
 # redis
 spring.cache.redis.enabled=true
 spring.cache.redis.enabled=true
 spring.redis.database=0
 spring.redis.database=0
-spring.redis.host=usky-cloud-redist 
+spring.redis.host=usky-cloud-redis
 spring.redis.port=6379
 spring.redis.port=6379
 spring.redis.password=123456
 spring.redis.password=123456
 spring.redis.timeout=10000
 spring.redis.timeout=10000

+ 3 - 0
fiveep-model/src/main/java/com/bizmatics/model/DeviceList.java

@@ -72,6 +72,9 @@ public class DeviceList implements Serializable {
      */
      */
     private Integer enable;
     private Integer enable;
 
 
+    /**
+     * 设备状态(0 正常,1 离线,77 告警,4 故障)
+     **/
     @TableField(exist = false)
     @TableField(exist = false)
     private Integer deviceStatus;
     private Integer deviceStatus;
 
 

+ 30 - 1
fiveep-model/src/main/java/com/bizmatics/model/SiteElectricityRecord.java

@@ -1,10 +1,15 @@
 package com.bizmatics.model;
 package com.bizmatics.model;
 
 
 import java.math.BigDecimal;
 import java.math.BigDecimal;
+
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.IdType;
+
 import java.time.LocalDate;
 import java.time.LocalDate;
+
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableId;
+
 import java.io.Serializable;
 import java.io.Serializable;
+
 import lombok.Data;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 import lombok.experimental.Accessors;
@@ -22,7 +27,7 @@ import lombok.experimental.Accessors;
 @Accessors(chain = true)
 @Accessors(chain = true)
 public class SiteElectricityRecord implements Serializable {
 public class SiteElectricityRecord implements Serializable {
 
 
-    private static final long serialVersionUID=1L;
+    private static final long serialVersionUID = 1L;
 
 
     /**
     /**
      * 站点日电费记录表ID
      * 站点日电费记录表ID
@@ -70,5 +75,29 @@ public class SiteElectricityRecord implements Serializable {
      */
      */
     private BigDecimal totalCost;
     private BigDecimal totalCost;
 
 
+    /**
+     * 尖 用量(Kwh)
+     */
+    private BigDecimal sharpPeak;
+
+    /**
+     * 峰 用量(Kwh)
+     */
+    private BigDecimal peak;
+
+    /**
+     * 平 用量(Kwh)
+     */
+    private BigDecimal flat;
+
+    /**
+     * 谷 用量(Kwh)
+     */
+    private BigDecimal valley;
+
+    /**
+     * 总电量(Kwh)
+     */
+    private BigDecimal totalElectricity;
 
 
 }
 }

+ 4 - 1
fiveep-persistence/src/main/java/com/bizmatics/persistence/mapper/DeviceMapper.java

@@ -59,5 +59,8 @@ public interface DeviceMapper extends CrudMapper<Device> {
 
 
     List<DeviceOneVo> deviceBoxList(@Param("siteId") Integer siteId);
     List<DeviceOneVo> deviceBoxList(@Param("siteId") Integer siteId);
 
 
-
+    List<DeviceList> deviceBranch(@Param("siteId") int siteId,
+                                  @Param("deviceType") int deviceType,
+                                  @Param("pageNum") int pageNum,
+                                  @Param("pageSize") int pageSize);
 }
 }

+ 41 - 10
fiveep-persistence/src/main/resources/mapper/mysql/DeviceMapper.xml

@@ -4,15 +4,15 @@
 
 
     <!-- 通用查询映射结果 -->
     <!-- 通用查询映射结果 -->
     <resultMap id="BaseResultMap" type="com.bizmatics.model.Device">
     <resultMap id="BaseResultMap" type="com.bizmatics.model.Device">
-        <id column="id" property="id" />
-        <result column="device_code" property="deviceCode" />
-        <result column="device_name" property="deviceName" />
-        <result column="site_id" property="siteId" />
-        <result column="device_address" property="deviceAddress" />
-        <result column="device_type" property="deviceType" />
-        <result column="install_time" property="installTime" />
-        <result column="creator" property="creator" />
-        <result column="enable" property="enable" />
+        <id column="id" property="id"/>
+        <result column="device_code" property="deviceCode"/>
+        <result column="device_name" property="deviceName"/>
+        <result column="site_id" property="siteId"/>
+        <result column="device_address" property="deviceAddress"/>
+        <result column="device_type" property="deviceType"/>
+        <result column="install_time" property="installTime"/>
+        <result column="creator" property="creator"/>
+        <result column="enable" property="enable"/>
     </resultMap>
     </resultMap>
     <select id="selectCount" resultType="java.lang.Integer">
     <select id="selectCount" resultType="java.lang.Integer">
         select count(1)
         select count(1)
@@ -43,7 +43,8 @@
         </where>
         </where>
     </select>
     </select>
     <select id="list" resultType="com.bizmatics.model.Device">
     <select id="list" resultType="com.bizmatics.model.Device">
-        select d.id,d.device_code,d.device_name,d.site_id,d.device_address,d.device_type,d.install_time,ds.device_status as deviceStatus,
+        select d.id,d.device_code,d.device_name,d.site_id,d.device_address,d.device_type,d.install_time,ds.device_status
+        as deviceStatus,
         s.installed_capacity as installedCapacity
         s.installed_capacity as installedCapacity
         from user_site as us
         from user_site as us
         inner join device_status as ds
         inner join device_status as ds
@@ -89,6 +90,36 @@
         </where>
         </where>
     </select>
     </select>
 
 
+    <select id="deviceBranch" resultType="com.bizmatics.model.DeviceList">
+        SELECT
+        a.*, c.rated_voltage, c.rated_current
+        FROM
+        device AS a
+        JOIN device_attribute AS c ON a.device_code = c.monitor_device_code
+        <where>
+            a.enable = 1
+            <if test="siteId != null and siteId != 0">
+                AND a.site_id = #{siteId}
+            </if>
+
+            <choose>
+                <!-- deviceType == 1 -->
+                <when test="deviceType == 1">
+                    AND a.device_type = 1
+                </when>
+                <!-- deviceType == 2 -->
+                <when test="deviceType == 2">
+                    AND a.device_type IN (3,4)
+                </when>
+            </choose>
+        </where>
+
+        <!-- 分页参数 -->
+        <if test="pageNum != null and pageSize != null">
+            LIMIT #{pageSize} OFFSET ${(pageNum - 1) * pageSize}
+        </if>
+    </select>
+
     <select id="CorrespondDeviceList" resultType="com.bizmatics.model.vo.CorrespondDeviceVO">
     <select id="CorrespondDeviceList" resultType="com.bizmatics.model.vo.CorrespondDeviceVO">
         SELECT
         SELECT
         a.id,
         a.id,

+ 16 - 0
fiveep-service/pom.xml

@@ -112,6 +112,22 @@
             <groupId>com.google.protobuf</groupId>
             <groupId>com.google.protobuf</groupId>
             <artifactId>protobuf-java</artifactId>
             <artifactId>protobuf-java</artifactId>
         </dependency>
         </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+        <!-- Apache POI -->
+<!--        <dependency>-->
+<!--            <groupId>org.apache.poi</groupId>-->
+<!--            <artifactId>poi</artifactId>-->
+<!--            <version>5.2.2</version>-->
+<!--        </dependency>-->
+<!--        <dependency>-->
+<!--            <groupId>org.apache.poi</groupId>-->
+<!--            <artifactId>poi-ooxml</artifactId>-->
+<!--            <version>5.4.0</version>-->
+<!--        </dependency>-->
     </dependencies>
     </dependencies>
 
 
 
 

+ 4 - 2
fiveep-service/src/main/java/com/bizmatics/service/DeviceService.java

@@ -37,7 +37,7 @@ public interface DeviceService extends CrudService<Device> {
      */
      */
     DeviceCountVO selectDeviceCountByType(Integer site);
     DeviceCountVO selectDeviceCountByType(Integer site);
 
 
-    List<Device> list(Integer userId,Integer siteId,Integer deviceStatus,Date startTime,Date endTime,String type);
+    List<Device> list(Integer userId, Integer siteId, Integer deviceStatus, Date startTime, Date endTime, String type);
 
 
     List<DeviceList> deviceList(String siteId);
     List<DeviceList> deviceList(String siteId);
 
 
@@ -57,7 +57,7 @@ public interface DeviceService extends CrudService<Device> {
 
 
     void variableCloning(Integer type, String newDeviceCode, String oldDeviceCode, String deviceName);
     void variableCloning(Integer type, String newDeviceCode, String oldDeviceCode, String deviceName);
 
 
-    List<Device> deviceListOne(Integer siteId,Integer deviceType);
+    List<Device> deviceListOne(Integer siteId, Integer deviceType);
 
 
     String deviceExport(String deviceName, Integer deviceType, Integer siteId);
     String deviceExport(String deviceName, Integer deviceType, Integer siteId);
 
 
@@ -67,4 +67,6 @@ public interface DeviceService extends CrudService<Device> {
 
 
 
 
     List<DeviceOneVo> deviceBoxList(Integer siteId);
     List<DeviceOneVo> deviceBoxList(Integer siteId);
+
+    List<DeviceList> deviceBranch(int siteId, int deviceType, int pageNum, int pageSize);
 }
 }

+ 27 - 4
fiveep-service/src/main/java/com/bizmatics/service/HtAnalogDataService.java

@@ -1,14 +1,14 @@
 package com.bizmatics.service;
 package com.bizmatics.service;
 
 
 import com.bizmatics.common.core.bean.ApiResult;
 import com.bizmatics.common.core.bean.ApiResult;
+import com.bizmatics.common.core.bean.CommonPage;
 import com.bizmatics.common.mvc.base.CrudService;
 import com.bizmatics.common.mvc.base.CrudService;
 import com.bizmatics.model.HtAnalogData;
 import com.bizmatics.model.HtAnalogData;
 import com.bizmatics.model.vo.*;
 import com.bizmatics.model.vo.*;
-import com.bizmatics.service.vo.CommonIcoVO;
-import com.bizmatics.service.vo.HadCountVO;
-import com.bizmatics.service.vo.RealScoreVO;
-import com.bizmatics.service.vo.TimeShareVO;
+import com.bizmatics.service.vo.*;
 
 
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
 import java.time.LocalDate;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.util.Date;
 import java.util.Date;
@@ -131,4 +131,27 @@ public interface HtAnalogDataService extends CrudService<HtAnalogData> {
      * @return HtAnalogEnergySegmentedVo
      * @return HtAnalogEnergySegmentedVo
      */
      */
     HtAnalogEnergySegmentedVo getSegmentedData(Integer siteId, String queryPeriod, LocalDateTime queryTime, String queryType);
     HtAnalogEnergySegmentedVo getSegmentedData(Integer siteId, String queryPeriod, LocalDateTime queryTime, String queryType);
+
+    /**
+     * 分时电量-表格统计
+     *
+     * @param request
+     * @return
+     */
+    CommonPage<TimeSharingElectricityResponseVO> timeSharingElectricity(TimeSharingElectricityRequestVO request);
+
+    /**
+     * 分时电量-趋势统计
+     *
+     * @param trendVO
+     * @return
+     */
+    List<ElectricityTrendResponseVO> trend(ElectricityTrendRequestVO trendVO);
+
+    /**
+     * 分时电量-导出
+     *
+     * @param request
+     */
+    void export(TimeSharingElectricityRequestVO request, HttpServletResponse response) throws IOException;
 }
 }

+ 40 - 39
fiveep-service/src/main/java/com/bizmatics/service/impl/DeviceServiceImpl.java

@@ -43,10 +43,7 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.IOException;
 import java.text.DateFormat;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
 
 
 /**
 /**
  * 设备
  * 设备
@@ -143,7 +140,7 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
                     for (int j = 0; j < deviceAnalogVariableList.size(); j++) {
                     for (int j = 0; j < deviceAnalogVariableList.size(); j++) {
                         if (deviceList.get(i).getId().equals(deviceAnalogVariableList.get(j).getMonitoringEquipment())) {
                         if (deviceList.get(i).getId().equals(deviceAnalogVariableList.get(j).getMonitoringEquipment())) {
                             DeviceAnalogVariableList deviceAnalogVariableListThree = new DeviceAnalogVariableList();
                             DeviceAnalogVariableList deviceAnalogVariableListThree = new DeviceAnalogVariableList();
-                            deviceAnalogVariableListThree.setVariableCoding(deviceAnalogVariableList.get(j).getVariableCoding()+"_"+deviceList.get(i).getId());
+                            deviceAnalogVariableListThree.setVariableCoding(deviceAnalogVariableList.get(j).getVariableCoding() + "_" + deviceList.get(i).getId());
                             deviceAnalogVariableListThree.setVariableName(deviceAnalogVariableList.get(j).getVariableName());
                             deviceAnalogVariableListThree.setVariableName(deviceAnalogVariableList.get(j).getVariableName());
                             deviceAnalogVariableListThree.setId(deviceAnalogVariableList.get(j).getId());
                             deviceAnalogVariableListThree.setId(deviceAnalogVariableList.get(j).getId());
                             deviceAnalogVariableListTwo.add(deviceAnalogVariableListThree);
                             deviceAnalogVariableListTwo.add(deviceAnalogVariableListThree);
@@ -159,7 +156,7 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
     }
     }
 
 
     @Override
     @Override
-    public List<DeviceOneVo> deviceBoxList(Integer siteId){
+    public List<DeviceOneVo> deviceBoxList(Integer siteId) {
         List<DeviceOneVo> deviceOneVo = baseMapper.deviceBoxList(siteId);
         List<DeviceOneVo> deviceOneVo = baseMapper.deviceBoxList(siteId);
         return deviceOneVo;
         return deviceOneVo;
     }
     }
@@ -198,16 +195,16 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
     @Override
     @Override
     public CommonPage<CorrespondDeviceVO> correspondDeviceList(String deviceName, int size, int current) {
     public CommonPage<CorrespondDeviceVO> correspondDeviceList(String deviceName, int size, int current) {
         List<SysUser> tenantDaya = userMapper.getTenantId(SecurityUtils.getLoginUser().getUser().getUserId());
         List<SysUser> tenantDaya = userMapper.getTenantId(SecurityUtils.getLoginUser().getUser().getUserId());
-        if (tenantDaya.size()<0) {
+        if (tenantDaya.size() < 0) {
             throw new BusinessException("无此租户,请联系管理员");
             throw new BusinessException("无此租户,请联系管理员");
         }
         }
-        List<CorrespondDeviceVO> correspondDeviceListOne = baseMapper.CorrespondDeviceList(deviceName, null, null,tenantDaya.get(0).getTenantId());
+        List<CorrespondDeviceVO> correspondDeviceListOne = baseMapper.CorrespondDeviceList(deviceName, null, null, tenantDaya.get(0).getTenantId());
         int total = 0;
         int total = 0;
         if (correspondDeviceListOne.size() > 0) {
         if (correspondDeviceListOne.size() > 0) {
             total = correspondDeviceListOne.size();
             total = correspondDeviceListOne.size();
         }
         }
         int startCurrent = (current - 1) * size;
         int startCurrent = (current - 1) * size;
-        List<CorrespondDeviceVO> correspondDeviceList = baseMapper.CorrespondDeviceList(deviceName, startCurrent, size,tenantDaya.get(0).getTenantId());
+        List<CorrespondDeviceVO> correspondDeviceList = baseMapper.CorrespondDeviceList(deviceName, startCurrent, size, tenantDaya.get(0).getTenantId());
         return new CommonPage<>(correspondDeviceList, total, size, current);
         return new CommonPage<>(correspondDeviceList, total, size, current);
     }
     }
 
 
@@ -231,7 +228,7 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
 
 
     @Override
     @Override
     public CommonPage<Device> videoMonitoringDeviceList(String deviceName, Integer deviceType, Integer siteId, Integer size, Integer current) {
     public CommonPage<Device> videoMonitoringDeviceList(String deviceName, Integer deviceType, Integer siteId, Integer size, Integer current) {
-        IPage<Device> page = new Page<Device>(current,size);
+        IPage<Device> page = new Page<Device>(current, size);
         LambdaQueryWrapper<Device> queryWrapper = Wrappers.lambdaQuery();
         LambdaQueryWrapper<Device> queryWrapper = Wrappers.lambdaQuery();
         queryWrapper.eq(Device::getSiteId, siteId).eq(Device::getEnable, 1);
         queryWrapper.eq(Device::getSiteId, siteId).eq(Device::getEnable, 1);
         if (deviceType != null && deviceType != 0) {
         if (deviceType != null && deviceType != 0) {
@@ -243,13 +240,13 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
 
 
         page = this.page(page, queryWrapper);
         page = this.page(page, queryWrapper);
         this.ToCommonPage(page);
         this.ToCommonPage(page);
-        return new CommonPage<>(page.getRecords(), page.getTotal(), page.getSize(),page.getCurrent() );
+        return new CommonPage<>(page.getRecords(), page.getTotal(), page.getSize(), page.getCurrent());
     }
     }
 
 
     @Override
     @Override
     public void variableCloning(Integer type, String newDeviceCode, String oldDeviceCode, String deviceName) {
     public void variableCloning(Integer type, String newDeviceCode, String oldDeviceCode, String deviceName) {
         SysUser user = SecurityUtils.getLoginUser().getUser();
         SysUser user = SecurityUtils.getLoginUser().getUser();
-        //查询出旧设备配置
+        // 查询出旧设备配置
         LambdaQueryWrapper<Device> queryWrapper = Wrappers.lambdaQuery();
         LambdaQueryWrapper<Device> queryWrapper = Wrappers.lambdaQuery();
         queryWrapper.eq(Device::getEnable, 1).eq(Device::getDeviceCode, oldDeviceCode);
         queryWrapper.eq(Device::getEnable, 1).eq(Device::getDeviceCode, oldDeviceCode);
         List<Device> deviceList = this.list(queryWrapper);
         List<Device> deviceList = this.list(queryWrapper);
@@ -258,10 +255,10 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
             LambdaQueryWrapper<Device> queryWrapperFour = Wrappers.lambdaQuery();
             LambdaQueryWrapper<Device> queryWrapperFour = Wrappers.lambdaQuery();
             queryWrapperFour.eq(Device::getEnable, 1).eq(Device::getDeviceCode, newDeviceCode);
             queryWrapperFour.eq(Device::getEnable, 1).eq(Device::getDeviceCode, newDeviceCode);
             List<Device> deviceListrFour = this.list(queryWrapperFour);
             List<Device> deviceListrFour = this.list(queryWrapperFour);
-            if (deviceListrFour.size()>0){
-                throw new BusinessException(newDeviceCode+"设备编号重复");
-            }else {
-                //设备表新增
+            if (deviceListrFour.size() > 0) {
+                throw new BusinessException(newDeviceCode + "设备编号重复");
+            } else {
+                // 设备表新增
                 Device device = new Device();
                 Device device = new Device();
                 device.setEnable(1);
                 device.setEnable(1);
                 device.setInstallTime(new Date());
                 device.setInstallTime(new Date());
@@ -277,14 +274,14 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
                 Integer deviceId = device.getId();
                 Integer deviceId = device.getId();
                 String deviceCode = device.getDeviceCode();
                 String deviceCode = device.getDeviceCode();
                 Integer siteId = device.getSiteId();
                 Integer siteId = device.getSiteId();
-                //设备状态表新增
+                // 设备状态表新增
                 DeviceStatus deviceStatus = new DeviceStatus();
                 DeviceStatus deviceStatus = new DeviceStatus();
                 deviceStatus.setDeviceStatus(1);
                 deviceStatus.setDeviceStatus(1);
                 deviceStatus.setDeviceCode(deviceCode);
                 deviceStatus.setDeviceCode(deviceCode);
                 deviceStatus.setStatusTime(new Date());
                 deviceStatus.setStatusTime(new Date());
                 deviceStatus.setSiteId(siteId);
                 deviceStatus.setSiteId(siteId);
                 deviceStatusService.save(deviceStatus);
                 deviceStatusService.save(deviceStatus);
-                //变量配置查询
+                // 变量配置查询
                 LambdaQueryWrapper<DeviceAnalogVariableList> queryWrapperOne = Wrappers.lambdaQuery();
                 LambdaQueryWrapper<DeviceAnalogVariableList> queryWrapperOne = Wrappers.lambdaQuery();
                 queryWrapperOne.eq(DeviceAnalogVariableList::getStatus, 1).eq(DeviceAnalogVariableList::getCommunicationEquipment, deviceList.get(0).getId());
                 queryWrapperOne.eq(DeviceAnalogVariableList::getStatus, 1).eq(DeviceAnalogVariableList::getCommunicationEquipment, deviceList.get(0).getId());
                 List<DeviceAnalogVariableList> deviceAnalogVariableList = deviceAnalogVariableListService.list(queryWrapperOne);
                 List<DeviceAnalogVariableList> deviceAnalogVariableList = deviceAnalogVariableListService.list(queryWrapperOne);
@@ -293,7 +290,7 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
                         DeviceAnalogVariableList deviceAnalogVariableListOne = new DeviceAnalogVariableList();
                         DeviceAnalogVariableList deviceAnalogVariableListOne = new DeviceAnalogVariableList();
                         deviceAnalogVariableListOne.setDeviceCode(newDeviceCode);
                         deviceAnalogVariableListOne.setDeviceCode(newDeviceCode);
                         deviceAnalogVariableListOne.setVariableName(deviceAnalogVariableList.get(i).getVariableName());
                         deviceAnalogVariableListOne.setVariableName(deviceAnalogVariableList.get(i).getVariableName());
-                        deviceAnalogVariableListOne.setVariableCoding(newDeviceCode+"_"+deviceAnalogVariableList.get(i).getVariableCoding().split("_")[1]);
+                        deviceAnalogVariableListOne.setVariableCoding(newDeviceCode + "_" + deviceAnalogVariableList.get(i).getVariableCoding().split("_")[1]);
                         deviceAnalogVariableListOne.setMonitoringEquipment(0);
                         deviceAnalogVariableListOne.setMonitoringEquipment(0);
                         deviceAnalogVariableListOne.setCommunicationEquipment(deviceId);
                         deviceAnalogVariableListOne.setCommunicationEquipment(deviceId);
                         deviceAnalogVariableListOne.setDataAddress(deviceAnalogVariableList.get(i).getDataAddress());
                         deviceAnalogVariableListOne.setDataAddress(deviceAnalogVariableList.get(i).getDataAddress());
@@ -313,7 +310,7 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
             queryWrapperOneA.eq(DeviceAnalogVariableList::getStatus, 1).eq(DeviceAnalogVariableList::getCommunicationEquipment, deviceList.get(0).getId());
             queryWrapperOneA.eq(DeviceAnalogVariableList::getStatus, 1).eq(DeviceAnalogVariableList::getCommunicationEquipment, deviceList.get(0).getId());
             List<DeviceAnalogVariableList> deviceAnalogVariableListOne = deviceAnalogVariableListService.list(queryWrapperOneA);
             List<DeviceAnalogVariableList> deviceAnalogVariableListOne = deviceAnalogVariableListService.list(queryWrapperOneA);
 
 
-            //克隆设备查询是否存在
+            // 克隆设备查询是否存在
             LambdaQueryWrapper<Device> queryWrapperTwo = Wrappers.lambdaQuery();
             LambdaQueryWrapper<Device> queryWrapperTwo = Wrappers.lambdaQuery();
             queryWrapperTwo.eq(Device::getEnable, 1).eq(Device::getDeviceCode, newDeviceCode);
             queryWrapperTwo.eq(Device::getEnable, 1).eq(Device::getDeviceCode, newDeviceCode);
             List<Device> deviceListTwo = this.list(queryWrapperTwo);
             List<Device> deviceListTwo = this.list(queryWrapperTwo);
@@ -335,7 +332,7 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
                     DeviceAnalogVariableList deviceAnalogVariableList = new DeviceAnalogVariableList();
                     DeviceAnalogVariableList deviceAnalogVariableList = new DeviceAnalogVariableList();
                     deviceAnalogVariableList.setDeviceCode(newDeviceCode);
                     deviceAnalogVariableList.setDeviceCode(newDeviceCode);
                     deviceAnalogVariableList.setVariableName(deviceAnalogVariableListOne.get(i).getVariableName());
                     deviceAnalogVariableList.setVariableName(deviceAnalogVariableListOne.get(i).getVariableName());
-                    deviceAnalogVariableList.setVariableCoding(newDeviceCode+"_"+deviceAnalogVariableListOne.get(i).getVariableCoding().split("_")[1]);
+                    deviceAnalogVariableList.setVariableCoding(newDeviceCode + "_" + deviceAnalogVariableListOne.get(i).getVariableCoding().split("_")[1]);
                     deviceAnalogVariableList.setMonitoringEquipment(0);
                     deviceAnalogVariableList.setMonitoringEquipment(0);
                     deviceAnalogVariableList.setCommunicationEquipment(deviceListTwo.get(0).getId());
                     deviceAnalogVariableList.setCommunicationEquipment(deviceListTwo.get(0).getId());
                     deviceAnalogVariableList.setDataType(deviceAnalogVariableListOne.get(i).getDataType());
                     deviceAnalogVariableList.setDataType(deviceAnalogVariableListOne.get(i).getDataType());
@@ -375,7 +372,7 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
                         Page<Device> page = new Page<>(i, 30);
                         Page<Device> page = new Page<>(i, 30);
                         LambdaQueryWrapper<Device> queryWrapper = Wrappers.lambdaQuery();
                         LambdaQueryWrapper<Device> queryWrapper = Wrappers.lambdaQuery();
                         queryWrapper.eq(Device::getEnable, 1);
                         queryWrapper.eq(Device::getEnable, 1);
-                        if (siteId!=0){
+                        if (siteId != 0) {
                             queryWrapper.eq(Device::getSiteId, siteId);
                             queryWrapper.eq(Device::getSiteId, siteId);
                         }
                         }
 
 
@@ -388,7 +385,7 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
 
 
                         page = this.page(page, queryWrapper);
                         page = this.page(page, queryWrapper);
 
 
-                        for (int j = 0; j < page.getRecords().size(); j++){
+                        for (int j = 0; j < page.getRecords().size(); j++) {
                             DeviceOne deviceOne = new DeviceOne();
                             DeviceOne deviceOne = new DeviceOne();
                             deviceOne.setDeviceCode(page.getRecords().get(j).getDeviceCode());
                             deviceOne.setDeviceCode(page.getRecords().get(j).getDeviceCode());
                             deviceOne.setDeviceName(page.getRecords().get(j).getDeviceName());
                             deviceOne.setDeviceName(page.getRecords().get(j).getDeviceName());
@@ -438,7 +435,7 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
         Workbook workbook = null;
         Workbook workbook = null;
         File file = null;
         File file = null;
         List<SysUser> tenantDaya = userMapper.getTenantId(SecurityUtils.getLoginUser().getUser().getUserId());
         List<SysUser> tenantDaya = userMapper.getTenantId(SecurityUtils.getLoginUser().getUser().getUserId());
-        if (tenantDaya.size()<0) {
+        if (tenantDaya.size() < 0) {
             throw new BusinessException("无此租户,请联系管理员");
             throw new BusinessException("无此租户,请联系管理员");
         }
         }
         try {
         try {
@@ -447,8 +444,8 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
                     (o, i) -> {
                     (o, i) -> {
                         List<CorrespondDeviceTwoVO> Active = new ArrayList<CorrespondDeviceTwoVO>();
                         List<CorrespondDeviceTwoVO> Active = new ArrayList<CorrespondDeviceTwoVO>();
                         int startCurrent = (i - 1) * 30;
                         int startCurrent = (i - 1) * 30;
-                        List<CorrespondDeviceVO> correspondDeviceList = baseMapper.CorrespondDeviceList(deviceName, startCurrent, 30,tenantDaya.get(0).getTenantId());
-                        for (int j = 0; j <correspondDeviceList.size(); j++){
+                        List<CorrespondDeviceVO> correspondDeviceList = baseMapper.CorrespondDeviceList(deviceName, startCurrent, 30, tenantDaya.get(0).getTenantId());
+                        for (int j = 0; j < correspondDeviceList.size(); j++) {
                             CorrespondDeviceTwoVO correspondDeviceTwoVO = new CorrespondDeviceTwoVO();
                             CorrespondDeviceTwoVO correspondDeviceTwoVO = new CorrespondDeviceTwoVO();
                             correspondDeviceTwoVO.setDeviceCode(correspondDeviceList.get(j).getDeviceCode());
                             correspondDeviceTwoVO.setDeviceCode(correspondDeviceList.get(j).getDeviceCode());
                             correspondDeviceTwoVO.setDeviceName(correspondDeviceList.get(j).getDeviceName());
                             correspondDeviceTwoVO.setDeviceName(correspondDeviceList.get(j).getDeviceName());
@@ -497,19 +494,19 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
         SysUser user = SecurityUtils.getLoginUser().getUser();
         SysUser user = SecurityUtils.getLoginUser().getUser();
         ImportParams params = new ImportParams();
         ImportParams params = new ImportParams();
         params.setHeadRows(1);
         params.setHeadRows(1);
-        String err="文件导入失败";
+        String err = "文件导入失败";
         try {
         try {
             List<DeviceImportVo> deviceImportVos = ExcelImportUtil.importExcel(multipartFile.getInputStream(),
             List<DeviceImportVo> deviceImportVos = ExcelImportUtil.importExcel(multipartFile.getInputStream(),
                     DeviceImportVo.class, params);
                     DeviceImportVo.class, params);
-            if (CollectionUtils.isNotEmpty(deviceImportVos)){
-                int rot=0;
-                for (DeviceImportVo deviceImportVo:deviceImportVos) {
+            if (CollectionUtils.isNotEmpty(deviceImportVos)) {
+                int rot = 0;
+                for (DeviceImportVo deviceImportVo : deviceImportVos) {
                     DeviceStatus deviceStatus = new DeviceStatus();
                     DeviceStatus deviceStatus = new DeviceStatus();
                     Device device = BeanMapperUtils.map(deviceImportVo, Device.class);
                     Device device = BeanMapperUtils.map(deviceImportVo, Device.class);
                     device.setEnable(1);
                     device.setEnable(1);
                     device.setCreator(user.getUserName());
                     device.setCreator(user.getUserName());
                     device.setInstallTime(new Date());
                     device.setInstallTime(new Date());
-                    try{
+                    try {
                         this.save(device);
                         this.save(device);
                         String deviceCode = device.getDeviceCode();
                         String deviceCode = device.getDeviceCode();
                         Integer siteId = device.getSiteId();
                         Integer siteId = device.getSiteId();
@@ -518,21 +515,25 @@ public class DeviceServiceImpl extends AbstractCrudService<DeviceMapper, Device>
                         deviceStatus.setStatusTime(new Date());
                         deviceStatus.setStatusTime(new Date());
                         deviceStatus.setSiteId(siteId);
                         deviceStatus.setSiteId(siteId);
                         deviceStatusService.save(deviceStatus);
                         deviceStatusService.save(deviceStatus);
-                    }catch (Exception e){
-                        int h=rot+2;
-                        err="文件导入失败,第"+h+"行数据导入失败";
-                        throw  new BusinessException(err);
+                    } catch (Exception e) {
+                        int h = rot + 2;
+                        err = "文件导入失败,第" + h + "行数据导入失败";
+                        throw new BusinessException(err);
                     }
                     }
                     rot++;
                     rot++;
                 }
                 }
-            }else {
-                err="文件不能为空";
+            } else {
+                err = "文件不能为空";
                 throw new BusinessException(err);
                 throw new BusinessException(err);
             }
             }
-        }catch (Exception e){
+        } catch (Exception e) {
             TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
             TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
-            throw  new BusinessException(err);
+            throw new BusinessException(err);
         }
         }
     }
     }
 
 
+    @Override
+    public List<DeviceList> deviceBranch(int siteId, int deviceType, int pageNum, int pageSize) {
+        return baseMapper.deviceBranch(siteId, deviceType, pageNum, pageSize);
+    }
 }
 }

+ 596 - 3
fiveep-service/src/main/java/com/bizmatics/service/impl/HtAnalogDataServiceImpl.java

@@ -5,13 +5,13 @@ import cn.afterturn.easypoi.excel.entity.ExportParams;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.bizmatics.common.core.bean.CommonPage;
 import com.bizmatics.common.core.exception.BusinessException;
 import com.bizmatics.common.core.exception.BusinessException;
 import com.bizmatics.common.core.util.*;
 import com.bizmatics.common.core.util.*;
 import com.bizmatics.common.mvc.base.AbstractCrudService;
 import com.bizmatics.common.mvc.base.AbstractCrudService;
 import com.bizmatics.common.spring.util.GlobalUtils;
 import com.bizmatics.common.spring.util.GlobalUtils;
 import com.bizmatics.common.spring.util.JsonUtils;
 import com.bizmatics.common.spring.util.JsonUtils;
 import com.bizmatics.model.*;
 import com.bizmatics.model.*;
-import com.bizmatics.model.utils.TimeRangeParams;
 import com.bizmatics.model.utils.TimeRangeUtils;
 import com.bizmatics.model.utils.TimeRangeUtils;
 import com.bizmatics.model.vo.*;
 import com.bizmatics.model.vo.*;
 import com.bizmatics.persistence.mapper.*;
 import com.bizmatics.persistence.mapper.*;
@@ -22,25 +22,34 @@ import com.bizmatics.service.util.SecurityUtils;
 import com.bizmatics.service.util.SiteFeeCacheService;
 import com.bizmatics.service.util.SiteFeeCacheService;
 import com.bizmatics.service.vo.*;
 import com.bizmatics.service.vo.*;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.core.type.TypeReference;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.checkerframework.checker.units.qual.A;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
+import javax.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.math.BigDecimal;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.math.RoundingMode;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.text.DateFormat;
 import java.text.DateFormat;
 import java.text.DecimalFormat;
 import java.text.DecimalFormat;
 import java.text.SimpleDateFormat;
 import java.text.SimpleDateFormat;
 import java.time.*;
 import java.time.*;
+import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.time.temporal.ChronoUnit;
 import java.time.temporal.TemporalAdjusters;
 import java.time.temporal.TemporalAdjusters;
 import java.util.*;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
 
 
@@ -88,6 +97,8 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
 
 
     private static final BigDecimal ZERO = BigDecimal.ZERO;
     private static final BigDecimal ZERO = BigDecimal.ZERO;
 
 
+    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
     @Override
     @Override
     public HadCountVO selectCount() {
     public HadCountVO selectCount() {
         HadCountVO hadCountVO = new HadCountVO();
         HadCountVO hadCountVO = new HadCountVO();
@@ -3028,5 +3039,587 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
                 .reduce(ZERO, BigDecimal::add);
                 .reduce(ZERO, BigDecimal::add);
     }
     }
 
 
+    @Override
+    public CommonPage<TimeSharingElectricityResponseVO> timeSharingElectricity(TimeSharingElectricityRequestVO request) {
+        /* ---------- 1. 参数兜底 ---------- */
+        Integer pageNum = request.getPageNum() == null ? 1 : request.getPageNum();
+        Integer pageSize = request.getPageSize() == null ? 20 : request.getPageSize();
+        if (request.getSiteId() == null) {
+            throw new BusinessException("站点ID不能为空");
+        }
+        if (CollectionUtils.isEmpty(request.getDeviceCodes())) {
+            throw new BusinessException("设备代码列表不能为空");
+        }
+        if (request.getStartTime() == null || request.getEndTime() == null) {
+            throw new BusinessException("起止时间不能为空");
+        }
+
+        /* ---------- 2. 分页查询 ---------- */
+        PageHelper.startPage(pageNum, pageSize);
+        LambdaQueryWrapper<SiteElectricityRecord> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SiteElectricityRecord::getSiteId, request.getSiteId())
+                .in(SiteElectricityRecord::getDeviceCode, request.getDeviceCodes())
+                .between(SiteElectricityRecord::getDate, request.getStartTime(), request.getEndTime())
+                .orderByAsc(SiteElectricityRecord::getDate, SiteElectricityRecord::getDeviceCode);
+
+        List<SiteElectricityRecord> records = siteElectricityRecordMapper.selectList(wrapper);
+
+        // 3. 按 deviceCode 分组汇总
+        List<TimeSharingElectricityResponseVO> list = records.stream()
+                .collect(Collectors.groupingBy(
+                        SiteElectricityRecord::getDeviceCode,
+                        LinkedHashMap::new,
+                        Collectors.reducing((a, b) -> {
+                            // 累加电量
+                            a.setSharpPeak(a.getSharpPeak().add(b.getSharpPeak()));
+                            a.setPeak(a.getPeak().add(b.getPeak()));
+                            a.setFlat(a.getFlat().add(b.getFlat()));
+                            a.setValley(a.getValley().add(b.getValley()));
+                            a.setTotalElectricity(a.getTotalElectricity().add(b.getTotalElectricity()));
+
+                            // 累加电费
+                            a.setSharpPeakCost(a.getSharpPeakCost().add(b.getSharpPeakCost()));
+                            a.setPeakCost(a.getPeakCost().add(b.getPeakCost()));
+                            a.setFlatCost(a.getFlatCost().add(b.getFlatCost()));
+                            a.setValleyCost(a.getValleyCost().add(b.getValleyCost()));
+                            a.setTotalCost(a.getTotalCost().add(b.getTotalCost()));
+                            return a;
+                        })
+                ))
+                .values().stream()
+                .map(opt -> opt.orElseThrow(() -> new RuntimeException("汇总数据不能为空")))
+                .map(r -> {
+                    TimeSharingElectricityResponseVO vo = new TimeSharingElectricityResponseVO();
+                    vo.setDeviceName(r.getDeviceCode());
+                    vo.setSharpNum(r.getSharpPeak());
+                    vo.setPeakNum(r.getPeak());
+                    vo.setFlatNum(r.getFlat());
+                    vo.setValleyNum(r.getValley());
+                    vo.setTotalNum(r.getTotalElectricity());
+                    vo.setSharpPrice(r.getSharpPeakCost());
+                    vo.setPeakPrice(r.getPeakCost());
+                    vo.setFlatPrice(r.getFlatCost());
+                    vo.setValleyPrice(r.getValleyCost());
+                    vo.setTotalPrice(r.getTotalCost());
+                    vo.setTime(request.getStartTime().toString() +
+                            " - " + request.getEndTime().toString());
+                    return vo;
+                })
+                .collect(Collectors.toList());
+
+        /* ---------- 4. 封装分页结果 ---------- */
+        PageInfo<TimeSharingElectricityResponseVO> pageInfo = new PageInfo<>(list);
+        return new CommonPage<>(list, pageInfo.getTotal(), pageNum, pageSize);
+    }
+
+    @Override
+    public List<ElectricityTrendResponseVO> trend(ElectricityTrendRequestVO request) {
+        // 1. 参数校验
+        if (request.getSiteId() == null) {
+            throw new BusinessException("站点ID不能为空");
+        }
+        if (CollectionUtils.isEmpty(request.getDeviceCodes())) {
+            throw new BusinessException("设备代码列表不能为空");
+        }
+        if (request.getStartTime() == null || request.getEndTime() == null || request.getStartTime().isAfter(request.getEndTime())) {
+            throw new BusinessException("起止时间异常");
+        }
+        if (request.getType() == null || !Arrays.asList(1, 2).contains(request.getType())) {
+            throw new BusinessException("查询类型必须为1(电量)或2(电费)");
+        }
+
+        LocalDate startDate = request.getStartTime();
+        LocalDate endDate = request.getEndTime();
+
+        // 2. 查询数据
+        LambdaQueryWrapper<SiteElectricityRecord> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SiteElectricityRecord::getSiteId, request.getSiteId())
+                .in(SiteElectricityRecord::getDeviceCode, request.getDeviceCodes())
+                .between(SiteElectricityRecord::getDate, startDate, endDate)
+                .orderByAsc(SiteElectricityRecord::getDeviceCode, SiteElectricityRecord::getDate);
+
+        List<SiteElectricityRecord> records = siteElectricityRecordMapper.selectList(wrapper);
+
+        // 3. 判断维度
+        long days = ChronoUnit.DAYS.between(startDate, endDate) + 1;
+        boolean monthMode = days > 31;
+
+        // 4. 选择字段函数(电量 or 电费)
+        boolean isElectricity = request.getType() == 1;
+        Function<SiteElectricityRecord, BigDecimal> sharpFn = isElectricity ?
+                SiteElectricityRecord::getSharpPeak : SiteElectricityRecord::getSharpPeakCost;
+        Function<SiteElectricityRecord, BigDecimal> peakFn = isElectricity ?
+                SiteElectricityRecord::getPeak : SiteElectricityRecord::getPeakCost;
+        Function<SiteElectricityRecord, BigDecimal> flatFn = isElectricity ?
+                SiteElectricityRecord::getFlat : SiteElectricityRecord::getFlatCost;
+        Function<SiteElectricityRecord, BigDecimal> valleyFn = isElectricity ?
+                SiteElectricityRecord::getValley : SiteElectricityRecord::getValleyCost;
+
+        records.forEach(r -> log.info("id={}, date={}, toString={}", r.getId(), r.getDate(), r.getDate().toString()));
+
+        // 5. 分组汇总
+        Map<String, Map<String, List<SiteElectricityRecord>>> group =
+                records.stream()
+                        .collect(Collectors.groupingBy(
+                                SiteElectricityRecord::getDeviceCode,
+                                LinkedHashMap::new,
+                                Collectors.groupingBy(r -> monthMode ?
+                                                YearMonth.from(r.getDate()).toString() : r.getDate().toString(),
+                                        LinkedHashMap::new,
+                                        Collectors.toList())
+                        ));
+
+
+        // 6. 转 VO
+        List<ElectricityTrendResponseVO> result = new ArrayList<>();
+        group.forEach((deviceCode, timeMap) -> {
+            ElectricityTrendResponseVO dev = new ElectricityTrendResponseVO();
+            dev.setDeviceCode(deviceCode);
+
+            List<ElectricityTrendVO> trendList = new ArrayList<>();
+            timeMap.forEach((timeKey, list) -> {
+
+                if (timeKey.contains("031") || timeKey.contains("-0031")) {
+                    throw new IllegalArgumentException("脏 timeKey 出现:" + timeKey);
+                }
+
+                BigDecimal sharp = list.stream().map(sharpFn).reduce(ZERO, BigDecimal::add);
+                BigDecimal peak = list.stream().map(peakFn).reduce(ZERO, BigDecimal::add);
+                BigDecimal flat = list.stream().map(flatFn).reduce(ZERO, BigDecimal::add);
+                BigDecimal valley = list.stream().map(valleyFn).reduce(ZERO, BigDecimal::add);
+
+                ElectricityTrendVO vo = new ElectricityTrendVO();
+                vo.setTime(timeKey);
+                vo.setSharp(sharp);
+                vo.setPeak(peak);
+                vo.setFlat(flat);
+                vo.setValley(valley);
+                trendList.add(vo);
+            });
+            dev.setData(trendList);
+            result.add(dev);
+        });
+
+        return result;
+    }
+
+    @Override
+    public void export(TimeSharingElectricityRequestVO request, HttpServletResponse response) throws IOException {
+        // 参数校验
+        if (request.getSiteId() == null) {
+            throw new BusinessException("站点ID不能为空");
+        }
+        if (CollectionUtils.isEmpty(request.getDeviceCodes())) {
+            throw new BusinessException("设备代码列表不能为空");
+        }
+        if (request.getStartTime() == null || request.getEndTime() == null) {
+            throw new BusinessException("起止时间不能为空");
+        }
+
+        // 格式化时间(解决之前的时间格式问题)
+        String start = formatter.format(request.getStartTime());
+        String end = formatter.format(request.getEndTime());
+
+        // 查询数据
+        LambdaQueryWrapper<SiteElectricityRecord> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SiteElectricityRecord::getSiteId, request.getSiteId())
+                .in(SiteElectricityRecord::getDeviceCode, request.getDeviceCodes())
+                .between(SiteElectricityRecord::getDate, request.getStartTime(), request.getEndTime())
+                .orderByAsc(SiteElectricityRecord::getDate, SiteElectricityRecord::getDeviceCode);
+
+        List<SiteElectricityRecord> records = siteElectricityRecordMapper.selectList(wrapper);
+        log.info("查询到的记录数: {}", records.size());
+        if (records.isEmpty()) {
+            throw new BusinessException("没有找到符合条件的数据");
+        }
+
+        // 按设备分组汇总数据
+        List<TimeSharingElectricityResponseVO> dataList = aggregateData(records, start, end);
+
+        // 处理分页
+        List<TimeSharingElectricityResponseVO> pageList = handlePagination(dataList, request);
+
+        // 准备导出信息
+        String deviceTypePrefix = request.getDeviceType() == 1 ? "支路" : "分项";
+        String sheetName = deviceTypePrefix + "分时用电";
+        String fileName = String.format("%s分时用电(%s-%s).xlsx", deviceTypePrefix, start, end);
+        String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
+
+        // 导出Excel
+        try (Workbook workbook = new XSSFWorkbook()) {
+            Sheet sheet = workbook.createSheet(sheetName);
+
+            // 创建样式
+            CellStyle titleStyle = createTitleStyle(workbook);    // 新增标题样式
+            CellStyle headerStyle = createHeaderStyle(workbook);
+            CellStyle dataStyle = createDataStyle(workbook);
+            CellStyle percentageStyle = createPercentageStyle(workbook);
+
+            // 构建表格结构
+            int currentRow = 0;
+            currentRow = createTitleRow(sheet, titleStyle, sheetName, currentRow);  // 使用标题样式
+            currentRow = createHeaderRows(sheet, headerStyle, currentRow, deviceTypePrefix);
+
+            // 设置列宽
+            setColumnWidths(sheet);
+
+            // 插入数据
+            currentRow = insertDataIntoSheet(sheet, pageList, dataStyle, percentageStyle, currentRow);
+
+            // 响应处理
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+            response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
+
+            try (OutputStream outputStream = response.getOutputStream()) {
+                workbook.write(outputStream);
+            }
+        } catch (Exception e) {
+            log.error("导出文件失败", e);
+            throw new BusinessException("导出文件失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 创建标题行
+     */
+    private int createTitleRow(Sheet sheet, CellStyle titleStyle, String title, int rowIndex) {
+        Row titleRow = sheet.createRow(rowIndex++);
+        Cell titleCell = titleRow.createCell(0);
+        titleCell.setCellValue(title);
+        titleCell.setCellStyle(titleStyle);
+        // 合并标题行(0行0列到0行11列)
+        sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, 11));
+        return rowIndex;
+    }
+
+    /**
+     * 创建表头行(包含单元格合并逻辑)
+     */
+    /**
+     * 创建表头行(包含单元格合并逻辑,确保所有单元格应用带边框的样式)
+     */
+    private int createHeaderRows(Sheet sheet, CellStyle headerStyle, int rowIndex, String deviceTypePrefix) {
+        // 第一级表头(rowIndex行)
+        Row headerRow = sheet.createRow(rowIndex);
+
+        // 1. 支路名称 - 合并两行(rowIndex和rowIndex+1行,0列)
+        sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex + 1, 0, 0));
+        // 为合并区域的两个行(rowIndex 和 rowIndex+1)的第0列单元格设置样式
+        for (int r = rowIndex; r <= rowIndex + 1; r++) {
+            Row row = sheet.getRow(r);
+            if (row == null) {
+                row = sheet.createRow(r);
+            }
+            Cell cell = row.getCell(0);
+            if (cell == null) {
+                cell = row.createCell(0);
+            }
+            cell.setCellValue(deviceTypePrefix + "名称");
+            cell.setCellStyle(headerStyle);
+        }
+
+        // 2. 尖峰 - 合并两列(rowIndex行,1-2列)
+        sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, 1, 2));
+        // 为合并区域的两个列(1 和 2)的单元格设置样式
+        for (int c = 1; c <= 2; c++) {
+            Cell cell = headerRow.getCell(c);
+            if (cell == null) {
+                cell = headerRow.createCell(c);
+            }
+            cell.setCellValue("尖峰");
+            cell.setCellStyle(headerStyle);
+        }
+
+        // 3. 峰 - 合并两列(rowIndex行,3-4列)
+        sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, 3, 4));
+        for (int c = 3; c <= 4; c++) {
+            Cell cell = headerRow.getCell(c);
+            if (cell == null) {
+                cell = headerRow.createCell(c);
+            }
+            cell.setCellValue("峰");
+            cell.setCellStyle(headerStyle);
+        }
+
+        // 4. 平 - 合并两列(rowIndex行,5-6列)
+        sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, 5, 6));
+        for (int c = 5; c <= 6; c++) {
+            Cell cell = headerRow.getCell(c);
+            if (cell == null) {
+                cell = headerRow.createCell(c);
+            }
+            cell.setCellValue("平");
+            cell.setCellStyle(headerStyle);
+        }
+
+        // 5. 谷 - 合并两列(rowIndex行,7-8列)
+        sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, 7, 8));
+        for (int c = 7; c <= 8; c++) {
+            Cell cell = headerRow.getCell(c);
+            if (cell == null) {
+                cell = headerRow.createCell(c);
+            }
+            cell.setCellValue("谷");
+            cell.setCellStyle(headerStyle);
+        }
+
+        // 6. 总 - 合并两列(rowIndex行,9-10列)
+        sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, 9, 10));
+        for (int c = 9; c <= 10; c++) {
+            Cell cell = headerRow.getCell(c);
+            if (cell == null) {
+                cell = headerRow.createCell(c);
+            }
+            cell.setCellValue("总");
+            cell.setCellStyle(headerStyle);
+        }
+
+        // 7. 谷电量占比 - 合并两行(rowIndex和rowIndex+1行,11列)
+        sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex + 1, 11, 11));
+        for (int r = rowIndex; r <= rowIndex + 1; r++) {
+            Row row = sheet.getRow(r);
+            if (row == null) {
+                row = sheet.createRow(r);
+            }
+            Cell cell = row.getCell(11);
+            if (cell == null) {
+                cell = row.createCell(11);
+            }
+            cell.setCellValue("谷电量占比");
+            cell.setCellStyle(headerStyle);
+        }
+
+        // 第二级表头(rowIndex+1行)
+        rowIndex++;
+        Row subHeaderRow = sheet.createRow(rowIndex);
+        String[] subHeaders = {"", "电量(kWh)", "电费(元)", "电量(kWh)", "电费(元)",
+                "电量(kWh)", "电费(元)", "电量(kWh)", "电费(元)",
+                "电量(kWh)", "电费(元)", ""};
+        for (int i = 0; i < subHeaders.length; i++) {
+            Cell cell = subHeaderRow.createCell(i);
+            cell.setCellValue(subHeaders[i]);
+            cell.setCellStyle(headerStyle);
+        }
+
+        return rowIndex + 1;
+    }
+
+    /**
+     * 设置列宽(增加标题行宽度)
+     */
+    private void setColumnWidths(Sheet sheet) {
+        // 为不同列设置更合理的宽度,第0列(支路名称)宽度增加
+        int[] columnWidths = {25, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 18};
+        for (int i = 0; i < columnWidths.length; i++) {
+            sheet.setColumnWidth(i, columnWidths[i] * 256);
+        }
+    }
+
+    // 创建标题样式(带边框、宋体,24号)
+    private CellStyle createTitleStyle(Workbook workbook) {
+        CellStyle style = workbook.createCellStyle();
+        // 设置边框
+        style.setBorderTop(BorderStyle.THIN);
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+
+        Font font = workbook.createFont();
+        font.setFontName("宋体");
+        font.setFontHeightInPoints((short) 24);
+        font.setBold(true);
+        style.setFont(font);
+        return style;
+    }
+
+    // 创建表头样式(带边框、宋体,12号,加粗)
+    private CellStyle createHeaderStyle(Workbook workbook) {
+        CellStyle style = workbook.createCellStyle();
+        // 设置边框
+        style.setBorderTop(BorderStyle.THIN);
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+
+        Font font = workbook.createFont();
+        font.setFontName("宋体");
+        font.setFontHeightInPoints((short) 12);
+        font.setBold(true);
+        style.setFont(font);
+        return style;
+    }
+
+    // 创建数据行样式(带边框、宋体,12号)
+    private CellStyle createDataStyle(Workbook workbook) {
+        CellStyle style = workbook.createCellStyle();
+        // 设置边框
+        style.setBorderTop(BorderStyle.THIN);
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+
+        Font font = workbook.createFont();
+        font.setFontName("宋体");
+        font.setFontHeightInPoints((short) 12);
+        style.setFont(font);
+        return style;
+    }
+
+    // 创建百分比样式(带边框、宋体,12号,百分比格式)
+    private CellStyle createPercentageStyle(Workbook workbook) {
+        CellStyle style = createDataStyle(workbook);
+        DataFormat format = workbook.createDataFormat();
+        style.setDataFormat(format.getFormat("0.00%"));
+        return style;
+    }
+
+    /**
+     * 汇总数据
+     */
+    private List<TimeSharingElectricityResponseVO> aggregateData(List<SiteElectricityRecord> records, String start, String end) {
+        return records.stream()
+                .collect(Collectors.groupingBy(
+                        SiteElectricityRecord::getDeviceCode,
+                        LinkedHashMap::new,
+                        Collectors.reducing((a, b) -> {
+                            // 累加电量
+                            a.setSharpPeak(a.getSharpPeak().add(b.getSharpPeak()));
+                            a.setPeak(a.getPeak().add(b.getPeak()));
+                            a.setFlat(a.getFlat().add(b.getFlat()));
+                            a.setValley(a.getValley().add(b.getValley()));
+                            a.setTotalElectricity(a.getTotalElectricity().add(b.getTotalElectricity()));
+
+                            // 累加电费
+                            a.setSharpPeakCost(a.getSharpPeakCost().add(b.getSharpPeakCost()));
+                            a.setPeakCost(a.getPeakCost().add(b.getPeakCost()));
+                            a.setFlatCost(a.getFlatCost().add(b.getFlatCost()));
+                            a.setValleyCost(a.getValleyCost().add(b.getValleyCost()));
+                            a.setTotalCost(a.getTotalCost().add(b.getTotalCost()));
+                            return a;
+                        })
+                ))
+                .values().stream()
+                .map(opt -> opt.orElseThrow(() -> new RuntimeException("汇总数据不能为空")))
+                .map(r -> {
+                    TimeSharingElectricityResponseVO vo = new TimeSharingElectricityResponseVO();
+                    vo.setDeviceName(r.getDeviceCode());
+                    vo.setSharpNum(r.getSharpPeak());
+                    vo.setPeakNum(r.getPeak());
+                    vo.setFlatNum(r.getFlat());
+                    vo.setValleyNum(r.getValley());
+                    vo.setTotalNum(r.getTotalElectricity());
+                    vo.setSharpPrice(r.getSharpPeakCost());
+                    vo.setPeakPrice(r.getPeakCost());
+                    vo.setFlatPrice(r.getFlatCost());
+                    vo.setValleyPrice(r.getValleyCost());
+                    vo.setTotalPrice(r.getTotalCost());
+                    vo.setTime(start + " - " + end);
+                    return vo;
+                })
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 处理分页
+     */
+    private List<TimeSharingElectricityResponseVO> handlePagination(List<TimeSharingElectricityResponseVO> dataList,
+                                                                    TimeSharingElectricityRequestVO request) {
+        int total = dataList.size();
+        int startIndex = (request.getPageNum() - 1) * request.getPageSize();
+        int endIndex = Math.min(startIndex + request.getPageSize(), total);
+
+        log.info("总记录数: {}, 起始索引: {}, 结束索引: {}", total, startIndex, endIndex);
+
+        if (startIndex > total) {
+            throw new BusinessException("起始索引无效");
+        }
+
+        return dataList.subList(startIndex, endIndex);
+    }
+
+    /**
+     * 插入数据到工作表
+     */
+    private int insertDataIntoSheet(Sheet sheet, List<TimeSharingElectricityResponseVO> dataList,
+                                    CellStyle dataStyle, CellStyle percentageStyle, int startRow) {
+        int currentRow = startRow;
+
+        for (TimeSharingElectricityResponseVO vo : dataList) {
+            Row row = sheet.createRow(currentRow++);
+            int cellIndex = 0;
+
+            // 支路名称
+            createCell(row, cellIndex++, vo.getDeviceName(), dataStyle);
+
+            // 尖峰数据
+            createCell(row, cellIndex++, vo.getSharpNum(), dataStyle);
+            createCell(row, cellIndex++, vo.getSharpPrice(), dataStyle);
+
+            // 峰数据
+            createCell(row, cellIndex++, vo.getPeakNum(), dataStyle);
+            createCell(row, cellIndex++, vo.getPeakPrice(), dataStyle);
+
+            // 平数据
+            createCell(row, cellIndex++, vo.getFlatNum(), dataStyle);
+            createCell(row, cellIndex++, vo.getFlatPrice(), dataStyle);
+
+            // 谷数据
+            createCell(row, cellIndex++, vo.getValleyNum(), dataStyle);
+            createCell(row, cellIndex++, vo.getValleyPrice(), dataStyle);
+
+            // 总数据
+            createCell(row, cellIndex++, vo.getTotalNum(), dataStyle);
+            createCell(row, cellIndex++, vo.getTotalPrice(), dataStyle);
+
+            // 谷电量占比(处理除零情况)
+            BigDecimal valleyRatio = calculateValleyRatio(vo);
+            createCell(row, cellIndex++, valleyRatio, percentageStyle);
+        }
+
+        return currentRow;
+    }
+
+    /**
+     * 创建单元格并设置值和样式
+     */
+    private void createCell(Row row, int cellIndex, Object value, CellStyle style) {
+        Cell cell = row.createCell(cellIndex);
+        cell.setCellStyle(style);
+
+        if (value == null) {
+            cell.setCellValue("");
+            return;
+        }
+
+        // 根据值类型设置单元格内容
+        if (value instanceof BigDecimal) {
+            cell.setCellValue(((BigDecimal) value).doubleValue());
+        } else if (value instanceof Number) {
+            cell.setCellValue(((Number) value).doubleValue());
+        } else {
+            cell.setCellValue(value.toString());
+        }
+    }
+
+    /**
+     * 计算谷电量占比(处理除零情况)
+     */
+    private BigDecimal calculateValleyRatio(TimeSharingElectricityResponseVO vo) {
+        try {
+            if (vo.getTotalNum() == null || vo.getTotalNum().compareTo(BigDecimal.ZERO) == 0) {
+                return BigDecimal.ZERO;
+            }
+            return vo.getValleyNum().divide(vo.getTotalNum(), 4, RoundingMode.HALF_UP);
+        } catch (Exception e) {
+            log.warn("计算谷电量占比失败", e);
+            return BigDecimal.ZERO;
+        }
+    }
 
 
 }
 }

+ 45 - 19
fiveep-service/src/main/java/com/bizmatics/service/job/SiteDailyElectricityCostTask.java

@@ -34,17 +34,20 @@ public class SiteDailyElectricityCostTask implements ApplicationRunner {
     /** 应用启动后立即执行一次 */
     /** 应用启动后立即执行一次 */
     @Override
     @Override
     public void run(ApplicationArguments args) {
     public void run(ApplicationArguments args) {
-        log.info("立即执行一次日电费记录");
+        log.info("立即执行一次日电量电费记录");
         // calculateDailyElectricityCost();
         // calculateDailyElectricityCost();
     }
     }
 
 
     // 每天凌晨0点过5分执行,计算前一天的用电费用
     // 每天凌晨0点过5分执行,计算前一天的用电费用
-    @Scheduled(cron = "0 5 0 * * ?")
+    //@Scheduled(cron = "0 5 0 * * ?")
+
+    // 每小时第5分钟执行一次
+    @Scheduled(cron = "0 5 * * * ?")
     public void calculateDailyElectricityCost() {
     public void calculateDailyElectricityCost() {
-        LocalDate yesterday = LocalDate.now().minusDays(1);
-        // LocalDate yesterday = LocalDate.now();
+        // LocalDate yesterday = LocalDate.now().minusDays(1);
+        LocalDate yesterday = LocalDate.now();
         // LocalDate yesterday = LocalDate.parse("2025-07-19");
         // LocalDate yesterday = LocalDate.parse("2025-07-19");
-        log.info("开始计算{}的用电费用", yesterday);
+        // log.info("开始计算{}的用电费用", yesterday);
 
 
         try {
         try {
             calculateElectricityCostForDate(yesterday);
             calculateElectricityCostForDate(yesterday);
@@ -121,6 +124,13 @@ public class SiteDailyElectricityCostTask implements ApplicationRunner {
         BigDecimal valleyCost = BigDecimal.ZERO;
         BigDecimal valleyCost = BigDecimal.ZERO;
         BigDecimal totalCost = BigDecimal.ZERO;
         BigDecimal totalCost = BigDecimal.ZERO;
 
 
+        // 初始化用电量
+        BigDecimal sharpPeak = BigDecimal.ZERO;
+        BigDecimal peak = BigDecimal.ZERO;
+        BigDecimal flat = BigDecimal.ZERO;
+        BigDecimal valley = BigDecimal.ZERO;
+        BigDecimal totalElectricity = BigDecimal.ZERO;
+
         // 计算每个时间段的电费
         // 计算每个时间段的电费
         for (int i = 1; i < electricityDataList.size(); i++) {
         for (int i = 1; i < electricityDataList.size(); i++) {
             ElectricityData prev = electricityDataList.get(i - 1);
             ElectricityData prev = electricityDataList.get(i - 1);
@@ -154,19 +164,24 @@ public class SiteDailyElectricityCostTask implements ApplicationRunner {
             // 计算电费:用电量 × 电价
             // 计算电费:用电量 × 电价
             BigDecimal cost = electricityUsage.multiply(config.getElectricityPrice());
             BigDecimal cost = electricityUsage.multiply(config.getElectricityPrice());
             totalCost = totalCost.add(cost).setScale(2, RoundingMode.HALF_UP);
             totalCost = totalCost.add(cost).setScale(2, RoundingMode.HALF_UP);
+            totalElectricity = totalElectricity.add(electricityUsage);
 
 
             switch (config.getPeakValleyAttribute()) {
             switch (config.getPeakValleyAttribute()) {
                 case 1: // 尖
                 case 1: // 尖
                     sharpPeakCost = sharpPeakCost.add(cost).setScale(2, RoundingMode.HALF_UP);
                     sharpPeakCost = sharpPeakCost.add(cost).setScale(2, RoundingMode.HALF_UP);
+                    sharpPeak = sharpPeak.add(electricityUsage);
                     break;
                     break;
                 case 2: // 峰
                 case 2: // 峰
                     peakCost = peakCost.add(cost).setScale(2, RoundingMode.HALF_UP);
                     peakCost = peakCost.add(cost).setScale(2, RoundingMode.HALF_UP);
+                    peak = peak.add(electricityUsage);
                     break;
                     break;
                 case 3: // 平
                 case 3: // 平
                     flatCost = flatCost.add(cost).setScale(2, RoundingMode.HALF_UP);
                     flatCost = flatCost.add(cost).setScale(2, RoundingMode.HALF_UP);
+                    flat = flat.add(electricityUsage);
                     break;
                     break;
                 case 4: // 谷
                 case 4: // 谷
                     valleyCost = valleyCost.add(cost).setScale(2, RoundingMode.HALF_UP);
                     valleyCost = valleyCost.add(cost).setScale(2, RoundingMode.HALF_UP);
+                    valley = valley.add(electricityUsage);
                     break;
                     break;
                 default:
                 default:
                     log.warn("未知的峰谷属性: {}", config.getPeakValleyAttribute());
                     log.warn("未知的峰谷属性: {}", config.getPeakValleyAttribute());
@@ -175,10 +190,15 @@ public class SiteDailyElectricityCostTask implements ApplicationRunner {
 
 
         // 保存计算结果
         // 保存计算结果
         saveElectricityRecord(siteId, deviceCode, date, sharpPeakCost, peakCost,
         saveElectricityRecord(siteId, deviceCode, date, sharpPeakCost, peakCost,
-                flatCost, valleyCost, totalCost);
-
-        log.info("站点{}设备{}在{}的电费计算完成:尖峰{}元,峰{}元,平{}元,谷{}元,总计{}元",
-                siteId, deviceCode, date, sharpPeakCost, peakCost, flatCost, valleyCost, totalCost);
+                flatCost, valleyCost, totalCost, sharpPeak, peak, flat, valley, totalElectricity);
+
+        log.info("站点{}设备{}在{}的电费计算完成:尖峰{}元({}kWh),峰{}元({}kWh),平{}元({}kWh),谷{}元({}kWh),总计{}元({}kwh)",
+                siteId, deviceCode, date,
+                sharpPeakCost, sharpPeak,
+                peakCost, peak,
+                flatCost, flat,
+                valleyCost, valley,
+                totalCost, totalElectricity);
     }
     }
 
 
     private List<TimePriceConfig> getTimePriceConfigs(Integer siteId, int month) {
     private List<TimePriceConfig> getTimePriceConfigs(Integer siteId, int month) {
@@ -250,17 +270,18 @@ public class SiteDailyElectricityCostTask implements ApplicationRunner {
     private void saveElectricityRecord(Integer siteId, String deviceCode, LocalDate date,
     private void saveElectricityRecord(Integer siteId, String deviceCode, LocalDate date,
                                        BigDecimal sharpPeakCost, BigDecimal peakCost,
                                        BigDecimal sharpPeakCost, BigDecimal peakCost,
                                        BigDecimal flatCost, BigDecimal valleyCost,
                                        BigDecimal flatCost, BigDecimal valleyCost,
-                                       BigDecimal totalCost) {
+                                       BigDecimal totalCost, BigDecimal sharpPeak,
+                                       BigDecimal peak, BigDecimal flat, BigDecimal valley,
+                                       BigDecimal totalElectricity) {
         String sql = "INSERT INTO site_electricity_record " +
         String sql = "INSERT INTO site_electricity_record " +
-                "(site_id, device_code, date, peak_cost, flat_cost, " +
-                "valley_cost, sharp_peak_cost, total_cost) " +
-                "VALUES (?, ?, ?, ?, ?, ?, ?, ?) " +
+                "(site_id, device_code, date, peak_cost, flat_cost, valley_cost, sharp_peak_cost, total_cost, " +
+                "sharp_peak, peak, flat, valley, total_electricity) " +
+                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) " +
                 "ON DUPLICATE KEY UPDATE " +
                 "ON DUPLICATE KEY UPDATE " +
-                "peak_cost = VALUES(peak_cost), " +
-                "flat_cost = VALUES(flat_cost), " +
-                "valley_cost = VALUES(valley_cost), " +
-                "sharp_peak_cost = VALUES(sharp_peak_cost), " +
-                "total_cost = VALUES(total_cost)";
+                "peak_cost = VALUES(peak_cost), flat_cost = VALUES(flat_cost), valley_cost = VALUES(valley_cost), " +
+                "sharp_peak_cost = VALUES(sharp_peak_cost), total_cost = VALUES(total_cost), " +
+                "sharp_peak = VALUES(sharp_peak), peak = VALUES(peak), " +
+                "flat = VALUES(flat), valley = VALUES(valley), total_electricity = VALUES(total_electricity)";
 
 
         try {
         try {
             jdbcTemplate.update(sql,
             jdbcTemplate.update(sql,
@@ -271,7 +292,12 @@ public class SiteDailyElectricityCostTask implements ApplicationRunner {
                     flatCost,
                     flatCost,
                     valleyCost,
                     valleyCost,
                     sharpPeakCost,
                     sharpPeakCost,
-                    totalCost
+                    totalCost,
+                    sharpPeak,
+                    peak,
+                    flat,
+                    valley,
+                    totalElectricity
             );
             );
             log.debug("成功保存站点{}设备{}的电费记录", siteId, deviceCode);
             log.debug("成功保存站点{}设备{}的电费记录", siteId, deviceCode);
         } catch (Exception e) {
         } catch (Exception e) {

+ 44 - 0
fiveep-service/src/main/java/com/bizmatics/service/vo/ElectricityTrendRequestVO.java

@@ -0,0 +1,44 @@
+package com.bizmatics.service.vo;
+
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/9/5
+ */
+@Data
+public class ElectricityTrendRequestVO {
+
+    /**
+     * 站点id
+     */
+    private Integer siteId;
+
+    /**
+     * 查询类型 1:电量,2:费用
+     */
+    private Integer type;
+
+    /**
+     * 开始时间
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startTime;
+
+    /**
+     * 结束时间
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endTime;
+
+    /**
+     * 设备编码列表
+     */
+    private List<String> deviceCodes;
+}

+ 27 - 0
fiveep-service/src/main/java/com/bizmatics/service/vo/ElectricityTrendResponseVO.java

@@ -0,0 +1,27 @@
+package com.bizmatics.service.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/9/5
+ */
+@Data
+public class ElectricityTrendResponseVO {
+
+    /**
+     * 设备名称
+     */
+    private String deviceCode;
+
+    /**
+     * 设备数据
+     */
+    private List<ElectricityTrendVO> data;
+}

+ 41 - 0
fiveep-service/src/main/java/com/bizmatics/service/vo/ElectricityTrendVO.java

@@ -0,0 +1,41 @@
+package com.bizmatics.service.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/9/5
+ */
+@Data
+public class ElectricityTrendVO {
+
+    /**
+     * 时间
+     */
+    private String time;
+
+    /**
+     * 尖
+     */
+    private BigDecimal sharp;
+
+    /**
+     * 峰
+     */
+    private BigDecimal peak;
+
+    /**
+     * 平
+     */
+    private BigDecimal flat;
+
+    /**
+     * 谷
+     */
+    private BigDecimal valley;
+
+}

+ 53 - 0
fiveep-service/src/main/java/com/bizmatics/service/vo/TimeSharingElectricityRequestVO.java

@@ -0,0 +1,53 @@
+package com.bizmatics.service.vo;
+
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/9/4
+ */
+@Data
+public class TimeSharingElectricityRequestVO {
+    /**
+     * 站点id
+     */
+    private Integer siteId;
+
+    /**
+     * 设备类型 1:支路 2:分项
+     */
+    private Integer deviceType;
+
+    /**
+     * 开始时间
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startTime;
+
+    /**
+     * 结束时间
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endTime;
+
+    /**
+     * 页数
+     */
+    private Integer pageNum;
+
+    /**
+     * 每页数量
+     */
+    private Integer pageSize;
+
+    /**
+     * 设备编码
+     */
+    private List<String> deviceCodes;
+}

+ 76 - 0
fiveep-service/src/main/java/com/bizmatics/service/vo/TimeSharingElectricityResponseVO.java

@@ -0,0 +1,76 @@
+package com.bizmatics.service.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/9/4
+ */
+@Data
+public class TimeSharingElectricityResponseVO {
+
+    /**
+     * 设备名称
+     */
+    private String deviceName;
+
+    /**
+     * 尖 电量
+     */
+    private BigDecimal sharpNum;
+
+    /**
+     * 峰 电量
+     */
+    private BigDecimal peakNum;
+
+    /**
+     * 平 电量
+     */
+    private BigDecimal flatNum;
+
+    /**
+     * 谷 电量
+     */
+    private BigDecimal valleyNum;
+
+    /**
+     * 总 电量
+     */
+    private BigDecimal totalNum;
+
+    /**
+     * 尖 电费
+     */
+    private BigDecimal sharpPrice;
+
+    /**
+     * 峰 电费
+     */
+    private BigDecimal peakPrice;
+
+    /**
+     * 平 电费
+     */
+    private BigDecimal flatPrice;
+
+    /**
+     * 谷 电费
+     */
+    private BigDecimal valleyPrice;
+
+    /**
+     * 总 电费
+     */
+    private BigDecimal totalPrice;
+
+    /**
+     * 数据时间区间
+     * 也用于导出文件名
+     */
+    private String time;
+}

+ 1 - 1
pom.xml

@@ -50,7 +50,7 @@
         <!--apache-->
         <!--apache-->
         <commons-lang3.version>3.11</commons-lang3.version>
         <commons-lang3.version>3.11</commons-lang3.version>
         <commons-beanutils.version>1.9.4</commons-beanutils.version>
         <commons-beanutils.version>1.9.4</commons-beanutils.version>
-        <commons-io.version>2.6</commons-io.version>
+        <commons-io.version>2.11.0</commons-io.version>
         <okhttp3.version>4.8.1</okhttp3.version>
         <okhttp3.version>4.8.1</okhttp3.version>
         <openCsv.version>4.6</openCsv.version>
         <openCsv.version>4.6</openCsv.version>