Browse Source

风机健康

shiyue 1 month ago
parent
commit
1df45d57b6
17 changed files with 1305 additions and 24 deletions
  1. 142 0
      energy-manage-common/src/main/java/com/energy/manage/common/po/healthscores/HealthscoresPO.java
  2. 96 0
      energy-manage-common/src/main/java/com/energy/manage/common/po/healthscores/HealthscoresWindPO.java
  3. 5 0
      energy-manage-common/src/main/java/com/energy/manage/common/po/windenginemill/WindEngineMillPO.java
  4. 5 0
      energy-manage-common/src/main/java/com/energy/manage/common/po/windfield/WindFieldPO.java
  5. 12 0
      energy-manage-service/src/main/java/com/energy/manage/service/constant/healthscores/HealthscoresTableConst.java
  6. 69 0
      energy-manage-service/src/main/java/com/energy/manage/service/controller/healthscores/HealthscoresController.java
  7. 52 20
      energy-manage-service/src/main/java/com/energy/manage/service/domain/vo/excel/WindEngineMillExcelVo.java
  8. 166 0
      energy-manage-service/src/main/java/com/energy/manage/service/domain/vo/healthscores/HealthOverviewListVO.java
  9. 39 0
      energy-manage-service/src/main/java/com/energy/manage/service/domain/vo/healthscores/HealthOverviewVO.java
  10. 105 0
      energy-manage-service/src/main/java/com/energy/manage/service/domain/vo/healthscores/HealthscoresTendencyVO.java
  11. 16 0
      energy-manage-service/src/main/java/com/energy/manage/service/domain/vo/healthscores/HealthscoresWindVO.java
  12. 64 0
      energy-manage-service/src/main/java/com/energy/manage/service/mappers/healthscores/HealthscoresMapper.java
  13. 42 0
      energy-manage-service/src/main/java/com/energy/manage/service/service/healthscores/HealthscoresService.java
  14. 252 0
      energy-manage-service/src/main/java/com/energy/manage/service/service/healthscores/impl/HealthscoresServiceImpl.java
  15. 4 4
      energy-manage-service/src/main/java/com/energy/manage/service/service/windenginemill/impl/WindEngineMillServiceImpl.java
  16. 181 0
      energy-manage-service/src/main/resources/mybatis/healthscores/HealthscoresMapper.xml
  17. 55 0
      energy-manage-service/src/test/java/ValidTableNamesTest.java

+ 142 - 0
energy-manage-common/src/main/java/com/energy/manage/common/po/healthscores/HealthscoresPO.java

@@ -0,0 +1,142 @@
+package com.energy.manage.common.po.healthscores;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class HealthscoresPO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     * 对应数据库字段:id (INT, 自增主键)
+     */
+    private Integer id;
+
+    /**
+     * 风场ID(内部命名)
+     * 对应数据库字段:field_code (VARCHAR(32), 非空,默认空字符串)
+     */
+    private String fieldId;
+
+    /**
+     * 风机ID(内部命名)
+     * 对应数据库字段:engine_code (VARCHAR(32), 非空,默认空字符串)
+     */
+    private String engineId;
+
+    /**
+     * 机型型号
+     */
+    private String machineTypeCode;
+
+    /**
+     * 综合健康评分 (0-100)
+     * 对应数据库字段:overall_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal overallScore;
+
+    /**
+     * 综合健康等级 (优/良/中/差)
+     * 对应数据库字段:overall_level (VARCHAR(10), 可为空)
+     */
+    private String overallLevel;
+
+    /**
+     * 叶轮健康评分 (0-100)
+     * 对应数据库字段:rotor_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal rotorScore;
+
+    /**
+     * 塔筒健康评分 (0-100)
+     * 对应数据库字段:tower_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal towerScore;
+
+    /**
+     * 发电机健康评分 (0-100)
+     * 对应数据库字段:generator_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal generatorScore;
+
+    /**
+     * 齿轮箱健康评分 (0-100)
+     * 对应数据库字段:gearbox_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal gearboxScore;
+
+    /**
+     * 主轴健康评分 (0-100)
+     * 对应数据库字段:main_shaft_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal mainShaftScore;
+
+    /**
+     * 变流器健康评分 (0-100)
+     * 对应数据库字段:converter_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal converterScore;
+
+    /**
+     * 偏航系统健康评分 (0-100)
+     * 对应数据库字段:yaw_system_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal yawSystemScore;
+
+    /**
+     * 变桨系统健康评分 (0-100)
+     * 对应数据库字段:pitch_system_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal pitchSystemScore;
+
+    /**
+     * 液压系统健康评分 (0-100)
+     * 对应数据库字段:hydraulic_system_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal hydraulicSystemScore;
+
+    /**
+     * 主控系统健康评分 (0-100)
+     * 对应数据库字段:control_system_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal controlSystemScore;
+
+    /**
+     * 数据来源时间 (yyyy-mm-dd)
+     * 对应数据库字段:source_datetime (DATE, 非空)
+     */
+    private Date sourceDatetime;
+
+    /**
+     * 评估入库时间戳 (yyyy-mm-dd hh:mm:ss)
+     * 对应数据库字段:create_time (DATETIME, 非空,默认当前时间)
+     */
+    private Date createTime;
+
+    /**
+     * 结构健康评分
+     */
+    private BigDecimal structureScore;
+
+    /**
+     * 部件健康评分
+     */
+    private BigDecimal componentScore;
+
+    /**
+     * 系统健康评分
+     */
+    private BigDecimal systemScore;
+
+
+
+}

+ 96 - 0
energy-manage-common/src/main/java/com/energy/manage/common/po/healthscores/HealthscoresWindPO.java

@@ -0,0 +1,96 @@
+package com.energy.manage.common.po.healthscores;
+
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class HealthscoresWindPO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     * 对应数据库字段:id (INT, 自增主键)
+     */
+    private Integer id;
+
+    /**
+     * 风场ID(客户内部编号)
+     * 对应数据库字段:fieldId (VARCHAR(32), 非空,默认空字符串)
+     */
+    private String fieldId;
+
+    /**
+     * 风场内健康等级为优的风机个数
+     * 对应数据库字段:excellent_count (INT, 可为空)
+     */
+    private Integer excellentCount;
+
+    /**
+     * 风场内健康等级为良的风机个数
+     * 对应数据库字段:good_count (INT, 可为空)
+     */
+    private Integer goodCount;
+
+    /**
+     * 风场内健康等级为中的风机个数
+     * 对应数据库字段:fair_count (INT, 可为空)
+     */
+    private Integer fairCount;
+
+    /**
+     * 风场内健康等级为差的风机个数
+     * 对应数据库字段:poor_count (INT, 可为空)
+     */
+    private Integer poorCount;
+
+    /**
+     * 风场综合健康评分 (0-100)
+     * 对应数据库字段:overall_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal overallScore;
+
+    /**
+     * 风场结构健康评分 (0-100)
+     * 对应数据库字段:structure_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal structureScore;
+
+    /**
+     * 风场系统健康评分 (0-100)
+     * 对应数据库字段:system_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal systemScore;
+
+    /**
+     * 风场部件健康评分 (0-100)
+     * 对应数据库字段:component_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal componentScore;
+
+    /**
+     * 数据来源时间 (yyyy-mm-dd)
+     * 对应数据库字段:source_datetime (DATE, 非空)
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
+    private Date sourceDatetime;
+
+    /**
+     * 评估入库时间戳 (yyyy-mm-dd hh:mm:ss)
+     * 对应数据库字段:create_time (DATETIME, 非空,默认当前时间)
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm",timezone = "GMT+8")
+    private Date createTime;
+
+
+
+}

+ 5 - 0
energy-manage-common/src/main/java/com/energy/manage/common/po/windenginemill/WindEngineMillPO.java

@@ -105,5 +105,10 @@ public class WindEngineMillPO {
      */
     private Date updateTime;
 
+    /**
+     * 塔筒形式类型
+     */
+    private Integer turbineTowerType;
+
 
 }

+ 5 - 0
energy-manage-common/src/main/java/com/energy/manage/common/po/windfield/WindFieldPO.java

@@ -20,6 +20,11 @@ import java.util.Date;
 public class WindFieldPO extends NewBaseDomain {
 
     /**
+     * 客户内部唯一编号
+     */
+    private String fieldId;
+
+    /**
      * 企业编号
      */
     private String companyCode;

+ 12 - 0
energy-manage-service/src/main/java/com/energy/manage/service/constant/healthscores/HealthscoresTableConst.java

@@ -0,0 +1,12 @@
+package com.energy.manage.service.constant.healthscores;
+
+public interface HealthscoresTableConst {
+
+    // 分表前缀
+    String TABLE_PREFIX = "healthscores_";
+
+    // 倒推天数
+    int LAST_N_DAYS = 365;
+
+
+}

+ 69 - 0
energy-manage-service/src/main/java/com/energy/manage/service/controller/healthscores/HealthscoresController.java

@@ -0,0 +1,69 @@
+package com.energy.manage.service.controller.healthscores;
+
+import com.energy.manage.common.reponse.ResultResp;
+import com.energy.manage.service.config.annotations.UserLoginToken;
+import com.energy.manage.service.controller.base.BaseServiceController;
+import com.energy.manage.service.domain.vo.healthscores.HealthOverviewVO;
+import com.energy.manage.service.domain.vo.healthscores.HealthscoresTendencyVO;
+import com.energy.manage.service.domain.vo.healthscores.HealthscoresWindVO;
+import com.energy.manage.service.domain.vo.homepage.WaitTaskVo;
+import com.energy.manage.service.service.healthscores.HealthscoresService;
+import com.energy.manage.service.service.homepage.HomePageService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author sy
+ * @desc
+ */
+@Api(value = "HealthscoresController",tags = "风机健康查询接口")
+@RestController
+@RequestMapping("/healthscores")
+public class HealthscoresController extends BaseServiceController {
+
+    @Autowired
+    private HealthscoresService healthscoresService;
+
+    @ApiOperation("首页风场健康台数统计数据")
+    @UserLoginToken
+    @PostMapping("/getHealthscoresWindList")
+    public ResultResp<List<HealthscoresWindVO>> getHealthscoresWindList(@RequestParam(value = "fieldCode",required = false) String fieldCode,
+                                                                @RequestParam(value = "datatime",required = false) String datatime){
+        List<HealthscoresWindVO> list = healthscoresService.getHealthscoresWind(fieldCode,datatime);
+        return success(list);
+    }
+
+
+
+    @ApiOperation("风场下所有风机健康查询概览页面")
+    @UserLoginToken
+    @PostMapping("/getHealthOverview")
+    public ResultResp<HealthOverviewVO> getHealthOverview(@RequestParam(value = "fieldCode") String fieldCode,
+                                                                        @RequestParam(value = "datatime",required = false) String datatime){
+        HealthOverviewVO healthOverviewVO = healthscoresService.getHealthOverview(fieldCode,datatime);
+        return success(healthOverviewVO);
+    }
+
+
+    @ApiOperation("风机按天数查询趋势图")
+    @UserLoginToken
+    @PostMapping("/getLastDaysTrend")
+    public ResultResp<HealthscoresTendencyVO> getLastDaysTrend(@RequestParam(value = "fieldId") String fieldId,
+                                                               @RequestParam(value = "engineId") String engineId,
+                                                               @RequestParam(value = "day") int day){
+        List<HealthscoresTendencyVO> list = healthscoresService.getLastDaysTrend(day,fieldId,engineId);
+        return success(list);
+    }
+
+
+
+
+
+
+
+
+}

+ 52 - 20
energy-manage-service/src/main/java/com/energy/manage/service/domain/vo/excel/WindEngineMillExcelVo.java

@@ -12,43 +12,75 @@ public class WindEngineMillExcelVo {
     /**
      * 机型编号
      */
-    @ExcelProperty(value = "机型号", index = 1)
+    @ExcelProperty(value = "机型号", index = 1)
     private String machineTypeCode;
     /**
-     * 机型名称
-     */
-    @ExcelProperty(value = "机型名称", index = 2)
-    private String machineTypeName;
-    /**
      * 厂商名称
      */
-    @ExcelProperty(value = "厂商名称", index = 3)
+    @ExcelProperty(value = "厂商名称", index = 2)
     private String manufacturerName;
     /**
-     * 厂商编号
-     */
-    @ExcelProperty(value = "厂商编号", index = 4)
-    private String manufacturerCode;
-    /**
      * 品牌
      */
-    @ExcelProperty(value = "品牌", index = 5)
+    @ExcelProperty(value = "品牌", index = 3)
     private String brand;
     /**
-     * 机型类型
-     */
-    @ExcelProperty(value = "机型类型", index = 6)
-    private Integer type;
-    /**
      * 塔筒高度
      */
-    @ExcelProperty(value = "塔筒高度", index = 7)
+    @ExcelProperty(value = "塔筒高度", index = 4)
     private String towerHeight;
     /**
      * 叶片长度
      */
-    @ExcelProperty(value = "叶片长度", index = 8)
+    @ExcelProperty(value = "叶片长度", index = 5)
     private String vaneLong;
+    /**
+     * 机型类型
+     */
+    @ExcelProperty(value = "驱动方式", index = 7)
+    private Integer curvedLotionType;
+
+    /**
+     * 叶轮直径
+     */
+    @ExcelProperty(value = "叶轮直径(m)", index = 8)
+    private Double rotorDiameter;
+
+    /**
+     * 传动比
+     */
+    @ExcelProperty(value = "传动比", index = 9)
+    private Double rotationalSpeedRatio;
+
+
+    /**
+     * 额定风速
+     */
+    @ExcelProperty(value = "额定风速", index = 10)
+    private Double ratedWindSpeed;
+
+
+    /**
+     * 切入风速
+     */
+    @ExcelProperty(value = "切入风速", index = 11)
+    private Double ratedCutInWindspeed;
+
+
+    /**
+     * 切出风速
+     */
+    @ExcelProperty(value = "切出风速", index = 12)
+    private Double ratedCutOutWindspeed;
+
+
+    /**
+     * 塔筒类型
+     */
+    @ExcelProperty(value = "塔筒类型", index = 13)
+    private String turbineTowerType;
+
+
 
 
 

+ 166 - 0
energy-manage-service/src/main/java/com/energy/manage/service/domain/vo/healthscores/HealthOverviewListVO.java

@@ -0,0 +1,166 @@
+package com.energy.manage.service.domain.vo.healthscores;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Getter
+@Setter
+@ApiModel
+public class HealthOverviewListVO {
+
+    /**
+     * 编号
+     */
+    @ApiModelProperty("")
+    private Integer id;
+    /**
+     * 风场ID(内部命名)
+     * 对应数据库字段:field_code (VARCHAR(32), 非空,默认空字符串)
+     */
+    @ApiModelProperty("")
+    private String fieldId;
+
+
+    /**
+     * 风机ID(内部命名)
+     * 对应数据库字段:engine_code (VARCHAR(32), 非空,默认空字符串)
+     */
+    @ApiModelProperty("")
+    private String engineId;
+
+    /**
+     * 风机名称
+     */
+    @ApiModelProperty("")
+    private String engineName;
+
+    /**
+     * 机型型号
+     */
+    @ApiModelProperty("")
+    private String machineTypeCode;
+
+    /**
+     * 综合健康评分 (0-100)
+     * 对应数据库字段:overall_score (DECIMAL(5,2), 可为空)
+     */
+    @ApiModelProperty("")
+    private BigDecimal overallScore;
+
+    /**
+     * 综合健康等级 (优/良/中/差)
+     * 对应数据库字段:overall_level (VARCHAR(10), 可为空)
+     */
+    @ApiModelProperty("")
+    private String overallLevel;
+
+    /**
+     * 叶轮健康评分 (0-100)
+     * 对应数据库字段:rotor_score (DECIMAL(5,2), 可为空)
+     */
+    @ApiModelProperty("")
+    private BigDecimal rotorScore;
+
+    /**
+     * 塔筒健康评分 (0-100)
+     * 对应数据库字段:tower_score (DECIMAL(5,2), 可为空)
+     */
+    @ApiModelProperty("")
+    private BigDecimal towerScore;
+
+    /**
+     * 发电机健康评分 (0-100)
+     * 对应数据库字段:generator_score (DECIMAL(5,2), 可为空)
+     */
+    @ApiModelProperty("")
+    private BigDecimal generatorScore;
+
+    /**
+     * 齿轮箱健康评分 (0-100)
+     * 对应数据库字段:gearbox_score (DECIMAL(5,2), 可为空)
+     */
+    @ApiModelProperty("")
+    private BigDecimal gearboxScore;
+
+    /**
+     * 主轴健康评分 (0-100)
+     * 对应数据库字段:main_shaft_score (DECIMAL(5,2), 可为空)
+     */
+    @ApiModelProperty("")
+    private BigDecimal mainShaftScore;
+
+    /**
+     * 变流器健康评分 (0-100)
+     * 对应数据库字段:converter_score (DECIMAL(5,2), 可为空)
+     */
+    @ApiModelProperty("")
+    private BigDecimal converterScore;
+
+    /**
+     * 偏航系统健康评分 (0-100)
+     * 对应数据库字段:yaw_system_score (DECIMAL(5,2), 可为空)
+     */
+    @ApiModelProperty("")
+    private BigDecimal yawSystemScore;
+
+    /**
+     * 变桨系统健康评分 (0-100)
+     * 对应数据库字段:pitch_system_score (DECIMAL(5,2), 可为空)
+     */
+    @ApiModelProperty("")
+    private BigDecimal pitchSystemScore;
+
+    /**
+     * 液压系统健康评分 (0-100)
+     * 对应数据库字段:hydraulic_system_score (DECIMAL(5,2), 可为空)
+     */
+    @ApiModelProperty("")
+    private BigDecimal hydraulicSystemScore;
+
+    /**
+     * 主控系统健康评分 (0-100)
+     * 对应数据库字段:control_system_score (DECIMAL(5,2), 可为空)
+     */
+    @ApiModelProperty("")
+    private BigDecimal controlSystemScore;
+
+    /**
+     * 数据来源时间 (yyyy-mm-dd)
+     * 对应数据库字段:source_datetime (DATE, 非空)
+     */
+    @ApiModelProperty("")
+    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
+    private Date sourceDatetime;
+
+    /**
+     * 评估入库时间戳 (yyyy-mm-dd hh:mm:ss)
+     * 对应数据库字段:create_time (DATETIME, 非空,默认当前时间)
+     */
+    @ApiModelProperty("")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm",timezone = "GMT+8")
+    private Date createTime;
+
+    /**
+     * 结构健康评分
+     */
+    @ApiModelProperty("")
+    private BigDecimal structureScore;
+
+    /**
+     * 部件健康评分
+     */
+    @ApiModelProperty("")
+    private BigDecimal componentScore;
+
+    /**
+     * 系统健康评分
+     */
+    @ApiModelProperty("")
+    private BigDecimal systemScore;
+}

+ 39 - 0
energy-manage-service/src/main/java/com/energy/manage/service/domain/vo/healthscores/HealthOverviewVO.java

@@ -0,0 +1,39 @@
+package com.energy.manage.service.domain.vo.healthscores;
+
+import com.energy.manage.common.po.healthscores.HealthscoresWindPO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@Getter
+@Setter
+@ApiModel
+public class HealthOverviewVO {
+
+    /**
+     * 风场健康信息
+     */
+    @ApiModelProperty("风场健康信息")
+    private HealthscoresWindVO healthscoresWindVO;
+
+
+    /**
+     * 健康概览风机集合
+     */
+    @ApiModelProperty("健康概览风机集合")
+    private List<HealthOverviewListVO>  healthOverviewListVOList;
+
+
+
+
+
+
+
+
+
+}

+ 105 - 0
energy-manage-service/src/main/java/com/energy/manage/service/domain/vo/healthscores/HealthscoresTendencyVO.java

@@ -0,0 +1,105 @@
+package com.energy.manage.service.domain.vo.healthscores;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.Date;
+
+@Getter
+@Setter
+@ApiModel
+public class HealthscoresTendencyVO {
+
+    // 空构造(MyBatis反射用)
+    public HealthscoresTendencyVO() {}
+
+    // 仅日期构造(补0时用)
+    public HealthscoresTendencyVO(LocalDate sourceDatetime) {
+        this.sourceDatetime = sourceDatetime;
+    }
+
+    /**
+     * 风场id
+     */
+    private String  fieldId;
+
+    /**
+     * 风机id
+     */
+    private String  engineId;
+
+    /**
+     * 坐标x
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
+    private LocalDate sourceDatetime;
+
+    /**
+     * 叶轮健康评分 (0-100)
+     * 对应数据库字段:rotor_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal rotorScore;
+
+    /**
+     * 塔筒健康评分 (0-100)
+     * 对应数据库字段:tower_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal towerScore;
+
+    /**
+     * 发电机健康评分 (0-100)
+     * 对应数据库字段:generator_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal generatorScore;
+
+    /**
+     * 齿轮箱健康评分 (0-100)
+     * 对应数据库字段:gearbox_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal gearboxScore;
+
+    /**
+     * 主轴健康评分 (0-100)
+     * 对应数据库字段:main_shaft_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal mainShaftScore;
+
+    /**
+     * 变流器健康评分 (0-100)
+     * 对应数据库字段:converter_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal converterScore;
+
+    /**
+     * 偏航系统健康评分 (0-100)
+     * 对应数据库字段:yaw_system_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal yawSystemScore;
+
+    /**
+     * 变桨系统健康评分 (0-100)
+     * 对应数据库字段:pitch_system_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal pitchSystemScore;
+
+    /**
+     * 液压系统健康评分 (0-100)
+     * 对应数据库字段:hydraulic_system_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal hydraulicSystemScore;
+
+    /**
+     * 主控系统健康评分 (0-100)
+     * 对应数据库字段:control_system_score (DECIMAL(5,2), 可为空)
+     */
+    private BigDecimal controlSystemScore;
+
+
+
+
+
+}

+ 16 - 0
energy-manage-service/src/main/java/com/energy/manage/service/domain/vo/healthscores/HealthscoresWindVO.java

@@ -0,0 +1,16 @@
+package com.energy.manage.service.domain.vo.healthscores;
+
+import com.energy.manage.common.po.healthscores.HealthscoresWindPO;
+import io.swagger.annotations.ApiModel;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+@ApiModel
+public class HealthscoresWindVO extends HealthscoresWindPO {
+
+
+}

+ 64 - 0
energy-manage-service/src/main/java/com/energy/manage/service/mappers/healthscores/HealthscoresMapper.java

@@ -0,0 +1,64 @@
+package com.energy.manage.service.mappers.healthscores;
+
+import com.energy.manage.common.mapper.MyMapper;
+import com.energy.manage.common.po.healthscores.HealthscoresPO;
+import com.energy.manage.common.po.powerwordcontract.PowerWordContractPO;
+import com.energy.manage.service.domain.vo.healthscores.HealthOverviewListVO;
+import com.energy.manage.service.domain.vo.healthscores.HealthscoresTendencyVO;
+import com.energy.manage.service.domain.vo.healthscores.HealthscoresWindVO;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Set;
+
+@Repository
+public interface HealthscoresMapper extends MyMapper<HealthscoresPO> {
+
+    /**
+     * 查询整个风场健康情况统计信息集合
+     * @param fieldId
+     * @param beginTime
+     * @param endTime
+     * @return
+     */
+    List<HealthscoresWindVO> selectWindScoreList(@Param("fieldId")String fieldId,
+                                                 @Param("beginTime")String beginTime,
+                                                 @Param("endTime")String endTime);
+
+    /**
+     * 查询单个风场健康情况统计信息
+     * @param fieldId
+     * @param beginTime
+     * @param endTime
+     * @return
+     */
+    HealthscoresWindVO selectWindHealthscoresScore(@Param("fieldId")String fieldId,
+                                                   @Param("beginTime")String beginTime,
+                                                   @Param("endTime")String endTime);
+
+    /**
+     * 查询风场下所有风机健康情况信息
+     * @param fieldId
+     * @param beginTime
+     * @param endTime
+     * @return
+     */
+    List<HealthOverviewListVO> selectHealthOverviewList(@Param("year")String year,
+                                                        @Param("fieldId")String fieldId,
+                                                        @Param("beginTime")String beginTime,
+                                                        @Param("endTime")String endTime);
+
+
+    /**
+     * 跨年分表查询近365天数据
+     */
+    List<HealthscoresTendencyVO> listHscoresLastays( @Param("fieldId") String fieldId,
+                                                     @Param("engineId") String engineId,
+                                                     @Param("startDate") LocalDate startDate,
+                                                     @Param("endDate") LocalDate endDate,
+                                                     @Param("tableNames") List<String> tableNames);
+
+
+}

+ 42 - 0
energy-manage-service/src/main/java/com/energy/manage/service/service/healthscores/HealthscoresService.java

@@ -0,0 +1,42 @@
+package com.energy.manage.service.service.healthscores;
+
+import com.energy.manage.service.domain.vo.healthscores.HealthOverviewListVO;
+import com.energy.manage.service.domain.vo.healthscores.HealthOverviewVO;
+import com.energy.manage.service.domain.vo.healthscores.HealthscoresTendencyVO;
+import com.energy.manage.service.domain.vo.healthscores.HealthscoresWindVO;
+
+import java.util.List;
+
+/**
+ * 健康查询接口
+ */
+public interface HealthscoresService {
+
+
+    /**
+     * 风场健康查询综合页面(包含首页)
+     * @param datatime
+     * @return
+     */
+    List<HealthscoresWindVO> getHealthscoresWind(String fieldCode,String datatime);
+
+
+    /**
+     * 风场下风机健康查询概览页面
+     * @param fieldCode
+     * @param datatime
+     * @return
+     */
+    HealthOverviewVO getHealthOverview(String fieldCode,String datatime);
+
+
+    /**
+     * 风机健康趋势图
+     * @param day
+     * @param fieldId
+     * @param engineId
+     * @return
+     */
+    List<HealthscoresTendencyVO> getLastDaysTrend(int day, String fieldId, String engineId);
+
+}

+ 252 - 0
energy-manage-service/src/main/java/com/energy/manage/service/service/healthscores/impl/HealthscoresServiceImpl.java

@@ -0,0 +1,252 @@
+package com.energy.manage.service.service.healthscores.impl;
+
+import com.energy.manage.common.po.windfield.WindFieldPO;
+import com.energy.manage.service.domain.vo.healthscores.HealthOverviewListVO;
+import com.energy.manage.service.domain.vo.healthscores.HealthOverviewVO;
+import com.energy.manage.service.domain.vo.healthscores.HealthscoresTendencyVO;
+import com.energy.manage.service.domain.vo.healthscores.HealthscoresWindVO;
+import com.energy.manage.service.mappers.healthscores.HealthscoresMapper;
+import com.energy.manage.service.mappers.windfield.WindFieldMapper;
+import com.energy.manage.service.service.healthscores.HealthscoresService;
+import groovy.util.logging.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Service
+@Slf4j
+public class HealthscoresServiceImpl implements HealthscoresService {
+
+    @Autowired
+    private HealthscoresMapper healthscoresMapper;
+
+    @Autowired
+    private WindFieldMapper windFieldMapper;
+
+    // 通用日期格式化器(线程安全,可全局复用)
+    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+    private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+
+    @Override
+    public List<HealthscoresWindVO> getHealthscoresWind(String fieldCode, String datatime) {
+
+        String fieldId = null;
+        if (!StringUtils.isEmpty(fieldCode)) {
+            WindFieldPO po = new WindFieldPO();
+            po.setFieldCode(fieldCode);
+            WindFieldPO windFieldPO = windFieldMapper.selectOne(po);
+            fieldId = windFieldPO.getFieldId();
+        }
+
+        String beginTime = null;
+        String endTime = null;
+        if (!StringUtils.isEmpty(datatime)) {
+            beginTime = appendTimeToString(datatime, 00, 00, 00);
+            endTime = appendTimeToString(datatime, 23, 59, 59);
+        } else {
+            beginTime = getYesterdayStartStr();
+            endTime = getYesterdayEnd().format(DATETIME_FORMATTER);
+        }
+
+        List<HealthscoresWindVO> list = healthscoresMapper.selectWindScoreList(fieldId, beginTime, endTime);
+        return list;
+    }
+
+
+    @Override
+    public HealthOverviewVO getHealthOverview(String fieldCode, String datatime) {
+
+        String fieldId = null;
+        if (!StringUtils.isEmpty(fieldCode)) {
+            WindFieldPO po = new WindFieldPO();
+            po.setFieldCode(fieldCode);
+            WindFieldPO windFieldPO = windFieldMapper.selectOne(po);
+            fieldId = windFieldPO.getFieldId();
+        }
+
+        String beginTime = null;
+        String endTime = null;
+        if (!StringUtils.isEmpty(datatime)) {
+            beginTime = appendTimeToString(datatime, 00, 00, 00);
+            endTime = appendTimeToString(datatime, 23, 59, 59);
+        } else {
+            beginTime = getYesterdayStartStr();
+            endTime = getYesterdayEnd().format(DATETIME_FORMATTER);
+        }
+
+        HealthOverviewVO healthOverviewVO = new HealthOverviewVO();
+        HealthscoresWindVO healthscoresWind = healthscoresMapper.selectWindHealthscoresScore(fieldId, beginTime, endTime);
+
+        if (healthscoresWind != null) {
+            healthOverviewVO.setHealthscoresWindVO(healthscoresWind);
+        }
+        String year = String.valueOf(LocalDate.now().getYear());
+        List<HealthOverviewListVO> overviewListVOS = healthscoresMapper.selectHealthOverviewList(year, fieldId, beginTime, endTime);
+        healthOverviewVO.setHealthOverviewListVOList(overviewListVOS);
+
+        return healthOverviewVO;
+    }
+
+    @Override
+    public List<HealthscoresTendencyVO> getLastDaysTrend(int day, String fieldId, String engineId) {
+        // 1. 校验入参(非空)
+        if (Objects.isNull(fieldId) || fieldId.isEmpty() || Objects.isNull(engineId) || engineId.isEmpty()) {
+            throw new IllegalArgumentException("风场ID和风机ID不能为空");
+        }
+
+        // 1. 计算起止日期
+        LocalDate[] range = getLastNDaysRange(day);
+        LocalDate startDate = range[0];
+        LocalDate endDate = range[1];
+
+        // 3. 生成连续的365天日期序列(基础维度,确保每个日期都有记录)
+        List<LocalDate> allDates = generateContinuousDates(startDate, endDate);
+
+        // 4. 确定要查询的表名(按年份拆分,如healthscores_2025、healthscores_2026)
+        List<String> tableNames = getValidTableNames(startDate, endDate);
+
+        // 3. 跨表查询数据
+        List<HealthscoresTendencyVO> hscoresLastays = healthscoresMapper.listHscoresLastays(fieldId, engineId, startDate, endDate, tableNames);
+
+        // 6. 封装已有数据到Map(key=日期,value=评分数据,方便快速匹配)
+        Map<LocalDate, HealthscoresTendencyVO> existDataMap = hscoresLastays.stream()
+                .collect(Collectors.toMap(
+                        HealthscoresTendencyVO::getSourceDatetime,
+                        data -> data,
+                        (oldVal, newVal) -> oldVal
+                ));
+
+        // 7. 补0处理:遍历所有日期,缺失则新建(所有评分字段默认0)
+        List<HealthscoresTendencyVO> finalResult = new ArrayList<>();
+        for (LocalDate date : allDates) {
+            HealthscoresTendencyVO score = existDataMap.getOrDefault(date, new HealthscoresTendencyVO(date));
+            // 补全风场/风机ID(前端展示用)
+            score.setFieldId(fieldId);
+            score.setEngineId(engineId);
+            finalResult.add(score);
+        }
+
+        return finalResult;
+    }
+
+
+    /**
+     * ====================== 当前接口使用日期工具 ======================
+     */
+
+    /**
+     * 给String类型的年月日拼接时分秒
+     *
+     * @param dateStr 年月日字符串(如 "2026-03-02")
+     * @param hour    小时
+     * @param minute  分钟
+     * @param second  秒
+     * @return 带时分秒的字符串(如 "2026-03-02 15:30:00")
+     */
+    private String appendTimeToString(String dateStr, int hour, int minute, int second) {
+        // 1. 解析为LocalDate(校验日期合法性)
+        LocalDate localDate = LocalDate.parse(dateStr, DATE_FORMATTER);
+        // 2. 拼接时分秒为LocalDateTime
+        LocalDateTime localDateTime = localDate.atTime(hour, minute, second);
+        // 3. 格式化为字符串
+        return localDateTime.format(DATETIME_FORMATTER);
+    }
+
+    /**
+     * 重载:获取昨天开始/结束时间的字符串格式
+     */
+    private String getYesterdayStartStr() {
+        return getYesterdayStart().format(DATETIME_FORMATTER);
+    }
+
+    private String getYesterdayEndStr() {
+        // 严格格式化为 23:59:59(去掉纳秒)
+        return getYesterdayEnd().format(DATETIME_FORMATTER).substring(0, 19);
+    }
+
+    /**
+     * 获取昨天的开始时间(yyyy-MM-dd 00:00:00)
+     *
+     * @return LocalDateTime
+     */
+    private LocalDateTime getYesterdayStart() {
+        // 1. 获取昨天的日期
+        LocalDate yesterday = LocalDate.now().minusDays(1);
+        // 2. 拼接 00:00:00 等价于 yesterday.atTime(0, 0, 0)
+        return yesterday.atStartOfDay();
+    }
+
+    /**
+     * 获取昨天的结束时间(yyyy-MM-dd 23:59:59)
+     *
+     * @return LocalDateTime
+     */
+    private LocalDateTime getYesterdayEnd() {
+        LocalDate yesterday = LocalDate.now().minusDays(1);
+        // 拼接 23:59:59
+        return yesterday.atTime(23, 59, 59);
+        // 若需严格的23:59:59,用:yesterday.atTime(23, 59, 59)
+    }
+
+    /**
+     * 获取近 N 天的开始、结束日期
+     * 参数days 为需要查几天的数据
+     */
+    private LocalDate[] getLastNDaysRange(int days) {
+        LocalDate endDate = LocalDate.now().minusDays(1);
+        LocalDate startDate = endDate.minusDays(days-1);
+        return new LocalDate[]{startDate, endDate};
+    }
+
+    /**
+     * 获取日期范围内涉及的所有年份(最多2个)
+     */
+    private Set<Integer> getYearSet(LocalDate start, LocalDate end) {
+        return Stream.of(start.getYear(), end.getYear())
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * 生成连续的日期序列(Java8 Stream实现)
+     */
+    private List<LocalDate> generateContinuousDates(LocalDate start, LocalDate end) {
+        long days = java.time.temporal.ChronoUnit.DAYS.between(start, end);
+        return Stream.iterate(start, date -> date.plusDays(1))
+                .limit(days + 1) // +1 包含结束日期
+                .collect(Collectors.toList());
+    }
+
+
+    /**
+     * 获取合法的表名列表(防SQL注入,仅允许healthscores_+4位数字)
+     */
+    private List<String> getValidTableNames(LocalDate start, LocalDate end) {
+        Set<String> tableNames = new HashSet<>();
+        String tablePrefix = "healthscores_";
+
+        // 遍历日期范围的所有年份
+        int startYear = start.getYear();
+        int endYear = end.getYear();
+        for (int year = startYear; year <= endYear; year++) {
+            tableNames.add(tablePrefix + year);
+        }
+
+        // 严格校验表名格式(防SQL注入)
+        tableNames.forEach(name -> {
+            if (!name.matches("^healthscores_\\d{4}$")) {
+                throw new IllegalArgumentException("非法表名:" + name + "(仅允许healthscores_四位数字格式)");
+            }
+        });
+
+        return new ArrayList<>(tableNames);
+    }
+
+}

+ 4 - 4
energy-manage-service/src/main/java/com/energy/manage/service/service/windenginemill/impl/WindEngineMillServiceImpl.java

@@ -64,7 +64,7 @@ public class WindEngineMillServiceImpl extends BaseServiceImpl<WindEngineMillPO>
     public boolean createEngineMill(WindEngineMillCreateDto windEngineMillCreateDto) {
 
         List<String> stringList = Lists.newArrayList();
-        String value = StrUtil.format("{},{}", windEngineMillCreateDto.getMachineTypeCode(), windEngineMillCreateDto.getManufacturerCode());
+        String value = StrUtil.format("{},{}", windEngineMillCreateDto.getMachineTypeCode(), windEngineMillCreateDto.getBrand());
         stringList.add(value);
 
         Integer count = windEngineMillMapper.selectWindEngineMillCount(stringList);
@@ -84,7 +84,7 @@ public class WindEngineMillServiceImpl extends BaseServiceImpl<WindEngineMillPO>
         // 生成厂商编号
         String mfNumber = IdPrefixEnum.WIND_EILL_MF_NUMBER.getCode().concat(IdGeneratorUtil.zeroFillUtil(cacheService.incr(ManagerRedisKeyConstant.build(ManagerRedisKeyConstant.IDGENERATOR_CONSTANTS_KEY, IdPrefixEnum.WIND_EILL_MF_NUMBER.getCode()))));
         windEngineMillPO.setManufacturerCode(mfNumber);
-        windEngineMillPO.setCombination(StrUtil.format("{},{}", windEngineMillCreateDto.getMachineTypeCode(), mfNumber));
+        windEngineMillPO.setCombination(StrUtil.format("{},{}", windEngineMillCreateDto.getMachineTypeCode(), windEngineMillCreateDto.getBrand()));
 
         return windEngineMillMapper.insertUseGeneratedKeys(windEngineMillPO) > 0;
     }
@@ -100,7 +100,7 @@ public class WindEngineMillServiceImpl extends BaseServiceImpl<WindEngineMillPO>
         }
         List<String> stringList = Lists.newArrayList();
         for (WindEngineMillExcelVo windEngineMillExcelVo : windFieldExceVos) {
-            String value = StrUtil.format("{},{}", windEngineMillExcelVo.getMachineTypeCode(), windEngineMillExcelVo.getManufacturerCode());
+            String value = StrUtil.format("{},{}", windEngineMillExcelVo.getMachineTypeCode(),windEngineMillExcelVo.getBrand());
             stringList.add(value);
         }
         Integer count = windEngineMillMapper.selectWindEngineMillCount(stringList);
@@ -114,7 +114,7 @@ public class WindEngineMillServiceImpl extends BaseServiceImpl<WindEngineMillPO>
             windEngineMillPO = new com.energy.manage.common.po.windenginemill.WindEngineMillPO();
             BeanUtil.copyProperties(windEngineMillExcelVo, windEngineMillPO);
             windEngineMillPO.setMillTypeCode(UUIDUtil.getShortUUID());
-            windEngineMillPO.setCombination(StrUtil.format("{},{}", windEngineMillExcelVo.getMachineTypeCode(), windEngineMillExcelVo.getManufacturerCode()));
+            windEngineMillPO.setCombination(StrUtil.format("{},{}", windEngineMillExcelVo.getMachineTypeCode(), windEngineMillExcelVo.getBrand()));
             windEngineMillPO.setCreateTime(new Date());
             windEngineMillPO.setUpdateTime(new Date());
             windEngineMillPO.setState(DeleteStatusEnum.NODELETE.getCode());

+ 181 - 0
energy-manage-service/src/main/resources/mybatis/healthscores/HealthscoresMapper.xml

@@ -0,0 +1,181 @@
+<?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">
+<mapper namespace="com.energy.manage.service.mappers.healthscores.HealthscoresMapper">
+
+    <!-- 查询风场健康聚合台数 -->
+    <select id="selectHealthOverviewCount" resultType="com.energy.manage.service.domain.vo.healthscores.HealthOverviewVO">
+        select
+        field_code as fieldCode,
+        overall_level as overallLevel,
+        count(overall_level) as overallTotal
+        from
+        healthscores_#{YEAR}
+        where
+        <if test="fieldCode!=null">
+            and weg.field_code = #{fieldCode}
+        </if>
+        group by overall_level
+    </select>
+
+    <!-- 风场健康综合统计查询 -->
+    <select id="selectWindScoreList" resultType="com.energy.manage.service.domain.vo.healthscores.HealthscoresWindVO">
+        SELECT
+        id as id,
+        field_id as fieldId,
+        excellent_count as excellentCount,
+        good_count as goodCount,
+        fair_count as fairCount,
+        poor_count as poorCount,
+        overall_score as overallScore,
+        structure_score as structureScore,
+        system_score as systemScore,
+        component_score as componentScore,
+        source_datetime as sourceDatetime,
+        create_time as createTime
+        FROM healthscores_wind
+        WHERE 1=1
+        <if test="fieldId!=null">
+            and field_id = #{fieldId}
+        </if>
+        <if test="beginTime != null and beginTime != ''">
+            and create_time  <![CDATA[>= ]]> #{beginTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            and create_time <![CDATA[<= ]]> #{endTime}
+        </if>
+        ORDER BY create_time DESC
+    </select>
+
+    <!-- 风场健康综合统计查询 -->
+    <select id="selectWindHealthscoresScore" resultType="com.energy.manage.service.domain.vo.healthscores.HealthscoresWindVO">
+        SELECT
+        id as id,
+        field_id as fieldId,
+        excellent_count as excellentCount,
+        good_count as goodCount,
+        fair_count as fairCount,
+        poor_count as poorCount,
+        overall_score as overallScore,
+        structure_score as structureScore,
+        system_score as systemScore,
+        component_score as componentScore,
+        source_datetime as sourceDatetime,
+        create_time as createTime
+        FROM healthscores_wind
+        WHERE 1=1
+        <if test="fieldId!=null">
+            and field_id = #{fieldId}
+        </if>
+        <if test="beginTime != null and beginTime != ''">
+            and create_time  <![CDATA[>= ]]>  #{beginTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            and create_time <![CDATA[<= ]]> #{endTime}
+        </if>
+        ORDER BY create_time DESC
+    </select>
+
+    <!-- 查询每个风场风机健康状态 -->
+    <select id="selectHealthOverviewList" resultType="com.energy.manage.service.domain.vo.healthscores.HealthOverviewListVO">
+        select
+        hs.id as id,
+        weg.engine_id as engineId,
+        weg.engine_name as engineName,
+        hs.overall_score as overallScore,
+        hs.overall_level as overallLevel,
+        hs.source_datetime as sourceDateTime,
+        hs.create_time as createTime
+        from
+        wind_engine_group weg
+        left join
+        healthscores_${year} hs
+        on  weg.engine_id = hs.engine_id
+        where 1=1
+        <if test="fieldId!=null">
+            and hs.field_id = #{fieldId}
+        </if>
+        <if test="beginTime != null and beginTime != ''">
+            and hs.create_time  <![CDATA[>= ]]>  #{beginTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            and hs.create_time <![CDATA[<= ]]> #{endTime}
+        </if>
+        order by hs.overall_score desc
+    </select>
+
+    <!-- 当年风机趋势图按周查询 -->
+    <select id="selectHealthscoresTendencyDay" resultType="com.energy.manage.service.domain.vo.healthscores.HealthscoresTendencyVO">
+    SELECT
+    ds.stat_date as xLabel,
+    rotor_score as rotorScore,
+    tower_score as towerScore,
+
+    generator_score as generatorScore,
+    gearbox_score as gearboxScore,
+    main_shaft_score as mainShaftScore,
+    converter_score as converterScore,
+
+    yaw_system_score as yawSystemScore,
+    pitch_system_score as pitchSystemScore,
+    hydraulic_system_score as hydraulicSystemScore,
+    control_system_score as controlSystemScore
+    FROM (
+        SELECT DATE_SUB(CURDATE(), INTERVAL 7 DAY) AS stat_date UNION ALL
+        SELECT DATE_SUB(CURDATE(), INTERVAL 6 DAY) UNION ALL
+        SELECT DATE_SUB(CURDATE(), INTERVAL 5 DAY) UNION ALL
+        SELECT DATE_SUB(CURDATE(), INTERVAL 4 DAY) UNION ALL
+        SELECT DATE_SUB(CURDATE(), INTERVAL 3 DAY) UNION ALL
+        SELECT DATE_SUB(CURDATE(), INTERVAL 2 DAY) UNION ALL
+        SELECT DATE_SUB(CURDATE(), INTERVAL 1 DAY)
+    ) ds
+    LEFT JOIN healthscores_#{year} h
+        ON h.source_datetime = ds.stat_date
+        AND h.engine_id = #{engineId}
+    GROUP BY ds.stat_date,rotor_score,tower_score,generator_score,gearbox_score,main_shaft_score,converter_score,yaw_system_score,pitch_system_score,hydraulic_system_score,control_system_score
+    ORDER BY ds.stat_date ASC
+    </select>
+
+
+    <resultMap id="BaseResultMap" type="com.energy.manage.service.domain.vo.healthscores.HealthscoresTendencyVO">
+        <result column="source_datetime" property="sourceDatetime" jdbcType="DATE"/>
+        <result column="rotor_score" property="rotorScore" jdbcType="DECIMAL"/>
+        <result column="tower_score" property="towerScore" jdbcType="DECIMAL"/>
+        <result column="generator_score" property="generatorScore" jdbcType="DECIMAL"/>
+        <result column="gearbox_score" property="gearboxScore" jdbcType="DECIMAL"/>
+        <result column="main_shaft_score" property="mainShaftScore" jdbcType="DECIMAL"/>
+        <result column="converter_score" property="converterScore" jdbcType="DECIMAL"/>
+        <result column="yaw_system_score" property="yawSystemScore" jdbcType="DECIMAL"/>
+        <result column="pitch_system_score" property="pitchSystemScore" jdbcType="DECIMAL"/>
+        <result column="hydraulic_system_score" property="hydraulicSystemScore" jdbcType="DECIMAL"/>
+        <result column="control_system_score" property="controlSystemScore" jdbcType="DECIMAL"/>
+    </resultMap>
+    <!-- 无定时天跨年分表查询 -->
+    <select id="listHscoresLastays" resultMap="BaseResultMap">
+        <foreach collection="tableNames" item="tableName" separator=" UNION ALL ">
+            SELECT
+            source_datetime,
+            rotor_score,
+            tower_score ,
+
+            generator_score,
+            gearbox_score,
+            main_shaft_score,
+            converter_score,
+
+            yaw_system_score,
+            pitch_system_score,
+            hydraulic_system_score,
+            control_system_score
+            FROM ${tableName}
+            WHERE  1=1
+            <if test="fieldId!=null">
+                and field_id = #{fieldId}
+            </if>
+            <if test="engineId!=null">
+                and engine_id = #{engineId}
+            </if>
+            and create_time BETWEEN #{startDate} AND #{endDate}
+        </foreach>
+    </select>
+
+</mapper>

+ 55 - 0
energy-manage-service/src/test/java/ValidTableNamesTest.java

@@ -0,0 +1,55 @@
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class ValidTableNamesTest {
+
+    public static void main(String[] age) {
+
+        long day = 7-1;
+
+        // 2. 确定日期范围:近365天(包含当天)
+        LocalDate endDate = LocalDate.now().minusDays(1);
+        LocalDate startDate = endDate.minusDays(day);
+
+        List<String> table = getValidTableNames(startDate, endDate);
+        System.out.println(table);
+
+        List<LocalDate> list =  generateContinuousDates(startDate,endDate);
+        System.out.println(list);
+
+    }
+
+
+    private static List<String> getValidTableNames(LocalDate start, LocalDate end) {
+        Set<String> tableNames = new HashSet<>();
+        String tablePrefix = "healthscores_";
+
+        // 遍历日期范围的所有年份
+        int startYear = start.getYear();
+        int endYear = end.getYear();
+        for (int year = startYear; year <= endYear; year++) {
+            tableNames.add(tablePrefix + year);
+        }
+
+        // 严格校验表名格式(防SQL注入)
+        tableNames.forEach(name -> {
+            if (!name.matches("^healthscores_\\d{4}$")) {
+                throw new IllegalArgumentException("非法表名:" + name + "(仅允许healthscores_四位数字格式)");
+            }
+        });
+
+        return new ArrayList<>(tableNames);
+    }
+
+    private static List<LocalDate> generateContinuousDates(LocalDate start, LocalDate end) {
+        long days = java.time.temporal.ChronoUnit.DAYS.between(start, end);
+        return Stream.iterate(start, date -> date.plusDays(1))
+                .limit(days + 1) // +1 包含结束日期
+                .collect(Collectors.toList());
+    }
+}