停电开始时间超过7天自动归为已复电
;停电分时、日K图、日累计停电用户需按停电类型拆分故障停电、计划停电、全部(20%)
This commit is contained in:
parent
b69dc1e3b4
commit
c7cbf45c2d
@ -7,6 +7,7 @@ import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 分时停电事件 -- mapper类
|
||||
@ -35,4 +36,21 @@ public interface DnerHourlyPowerOutageEventMapper extends BaseMapper<DnerHourlyP
|
||||
List<DnerHourlyPowerOutageEvent> selectByOrgCodesAndDataTime(@Param("orgCodes") List<String> orgCodes,
|
||||
@Param("startDate") String startDate,
|
||||
@Param("endDate") String endDate);
|
||||
|
||||
/**
|
||||
* 查询 outageState=2 且按 orgCode+日期分组后最小 dataTime 早于指定时间的分组列表
|
||||
* 返回 Map 包含 orgCode、dateGroup(yyyy-MM-dd) 字段
|
||||
*
|
||||
* @param beforeTime 截止时间(当前时间减7天)
|
||||
* @return 超期 orgCode+日期分组列表
|
||||
*/
|
||||
List<Map<String, Object>> selectExpiredDateGroups(@Param("beforeTime") String beforeTime);
|
||||
|
||||
/**
|
||||
* 按 orgCode+日期分组批量将 outageState 更新为 3
|
||||
*
|
||||
* @param groups orgCode+dateGroup 组合列表
|
||||
* @return 更新行数
|
||||
*/
|
||||
int batchUpdateOutageStateByGroups(@Param("groups") List<Map<String, String>> groups);
|
||||
}
|
||||
|
||||
@ -103,6 +103,16 @@ public class DnerDailyPowerOutageEvent {
|
||||
*/
|
||||
private Integer scheduledUserCount;
|
||||
|
||||
/**
|
||||
* 已复电停电影响用户数
|
||||
*/
|
||||
private Integer restoredUserCount;
|
||||
|
||||
/**
|
||||
* 未复电停电影响用户数
|
||||
*/
|
||||
private Integer notRestoredUserCount;
|
||||
|
||||
/**
|
||||
* 停电状态(1-待停电;2-停电中;3-已复电)
|
||||
*/
|
||||
|
||||
@ -20,4 +20,11 @@ public interface IDnerHourlyPowerOutageEventService extends IService<DnerHourlyP
|
||||
* @return 返回结果
|
||||
*/
|
||||
HourlyPowerOutageEventChartVO queryIntradayData(String orgCode, String startDate, String endDate);
|
||||
|
||||
/**
|
||||
* 停电开始时间超过7天自动归为已复电
|
||||
*
|
||||
*/
|
||||
void setResumedScheduledTask();
|
||||
|
||||
}
|
||||
|
||||
@ -244,6 +244,10 @@ public class DnerDailyPowerOutageEventBatchService {
|
||||
daily.setExtremeWindSpeedHourly(fmt(list.stream().mapToDouble(e -> toDouble(e.getExtremeWindSpeedHourly())).max().orElse(0.0)));
|
||||
daily.setPowerOutageDuration(fmt(list.stream().mapToDouble(e -> toDouble(e.getPowerOutageDuration())).max().orElse(0.0)));
|
||||
|
||||
daily.setFaultUserCount(list.stream().filter(Objects::nonNull).map(DnerHourlyPowerOutageEvent::getFaultUserCount).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
|
||||
daily.setScheduledUserCount(list.stream().filter(Objects::nonNull).map(DnerHourlyPowerOutageEvent::getScheduledUserCount).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
|
||||
daily.setRestoredUserCount(list.stream().filter(Objects::nonNull).map(DnerHourlyPowerOutageEvent::getRestoredUserCount).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
|
||||
daily.setNotRestoredUserCount(list.stream().filter(Objects::nonNull).map(DnerHourlyPowerOutageEvent::getNotRestoredUserCount).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
|
||||
return daily;
|
||||
} catch (Exception e) {
|
||||
log.error("转换日K线数据失败 - 日期: {}, 区域: {}, 错误: {}", date, orgCode, e.getMessage(), e);
|
||||
|
||||
@ -7,13 +7,14 @@ import com.southern.power.grid.entity.HourlyChartCollectVO;
|
||||
import com.southern.power.grid.entity.HourlyPowerOutageEventChartVO;
|
||||
import com.southern.power.grid.service.IDnerHourlyPowerOutageEventService;
|
||||
import com.southern.power.grid.utils.TimeUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -23,6 +24,7 @@ import java.util.stream.Collectors;
|
||||
* @author: junzhangfm
|
||||
* @date: 2026/3/13
|
||||
**/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DnerHourlyPowerOutageEventServiceImpl
|
||||
extends ServiceImpl<DnerHourlyPowerOutageEventMapper, DnerHourlyPowerOutageEvent>
|
||||
@ -85,5 +87,53 @@ public class DnerHourlyPowerOutageEventServiceImpl
|
||||
result.getWindList().add(0.0); // 小时极大风速
|
||||
}
|
||||
|
||||
/**
|
||||
* 每批次更新的日期分组数量,控制单条 SQL 的 IN 列表长度
|
||||
*/
|
||||
private static final int BATCH_SIZE = 200;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void setResumedScheduledTask() {
|
||||
// 7天前的时间点,格式与 data_time 字段一致(yyyy-MM-dd HH:mm)
|
||||
String beforeTime = LocalDateTime.now()
|
||||
.minusDays(7)
|
||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00:00"));
|
||||
|
||||
// 1. 按 orgCode+日期 分组聚合,只返回超期的分组标识,不拉取业务行数据
|
||||
List<Map<String, Object>> expiredGroups =
|
||||
dnerHourlyPowerOutageEventMapper.selectExpiredDateGroups(beforeTime);
|
||||
|
||||
if (expiredGroups == null || expiredGroups.isEmpty()) {
|
||||
log.info("[setResumedScheduledTask] 无超期停电数据,跳过更新");
|
||||
return;
|
||||
}
|
||||
|
||||
// 转换为 Map<String, String> 供 XML foreach 使用
|
||||
List<Map<String, String>> groups = expiredGroups.stream().map(m -> {
|
||||
Map<String, String> g = new HashMap<>(4);
|
||||
g.put("orgCode", String.valueOf(m.get("orgCode")));
|
||||
g.put("dateGroup", String.valueOf(m.get("dateGroup")));
|
||||
return g;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
log.info("[setResumedScheduledTask] 共 {} 个超期分组(orgCode+日期),开始批量更新", groups.size());
|
||||
|
||||
// 2. 分批次执行 UPDATE,控制每条 SQL 的 OR 条件数量,避免过长
|
||||
int total = 0;
|
||||
for (
|
||||
int i = 0; i < groups.size(); i += BATCH_SIZE) {
|
||||
List<Map<String, String>> batch = groups.subList(i, Math.min(i + BATCH_SIZE, groups.size()));
|
||||
int updated = dnerHourlyPowerOutageEventMapper.batchUpdateOutageStateByGroups(batch);
|
||||
total += updated;
|
||||
log.info("[setResumedScheduledTask] 批次 {}/{} 完成,本批更新 {} 行",
|
||||
(i / BATCH_SIZE + 1),
|
||||
(int) Math.ceil((double) groups.size() / BATCH_SIZE),
|
||||
updated);
|
||||
}
|
||||
|
||||
log.info("[setResumedScheduledTask] 全部完成,累计更新 {} 行", total);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -4,15 +4,11 @@ import com.southern.power.grid.dao.DnerHourlyPowerOutageEventMapper;
|
||||
import com.southern.power.grid.dao.NwSiteAreaConfigurationMapper;
|
||||
import com.southern.power.grid.dao.RegionalWeatherDataMapper;
|
||||
import com.southern.power.grid.dao.WeatherSiteAreaConfigurationMapper;
|
||||
import com.southern.power.grid.entity.DataExcelEntity;
|
||||
import com.southern.power.grid.entity.DnerHourlyPowerOutageEvent;
|
||||
import com.southern.power.grid.entity.NwSiteAreaConfiguration;
|
||||
import com.southern.power.grid.entity.RegionalWeatherData;
|
||||
import com.southern.power.grid.entity.WeatherSiteAreaConfiguration;
|
||||
import com.southern.power.grid.entity.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
@ -77,16 +73,37 @@ public class HourlyOutageExcelProcessService {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// 只有当前不是【已复电】状态,才需要判断
|
||||
if (!"已复电".equals(row.getOutageState())) {
|
||||
boolean needSetRestored = false;
|
||||
|
||||
// 场景1:停电时长为空 → 用当前时间 - 开始时间 判断是否超7天
|
||||
if (ObjectUtils.isEmpty(row.getLengthOutage())) {
|
||||
needSetRestored = LocalDateTime.now().isAfter(row.getStartTime().plusDays(7));
|
||||
}
|
||||
// 场景2:停电时长不为空 → 直接判断时长是否≥7天
|
||||
else {
|
||||
needSetRestored = row.getLengthOutage() >= 7L * 24 * 60;
|
||||
}
|
||||
|
||||
// 满足条件则设置为已复电
|
||||
if (needSetRestored) {
|
||||
row.setOutageState("已复电");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 3.1 根据南网省/市/区县 → district_code
|
||||
String districtCode = findDistrictCode(row.getProvince(), row.getCity(), row.getDistrict());
|
||||
if (districtCode == null) {
|
||||
// 找不到映射,可记录日志或统计
|
||||
log.info("districtCode is null! {}, {}, {}", row.getProvince(), row.getCity(), row.getDistrict());
|
||||
log.info("区域编码没有找到! {}, {}, {}", row.getProvince(), row.getCity(), row.getDistrict());
|
||||
continue;
|
||||
}
|
||||
// 3.2 获取区域时段内气象数据
|
||||
// 3.2 获取区域时段内气象数据(需要包含开始时间的整时数据)
|
||||
List<RegionalWeatherData> regionalWeatherDataList =
|
||||
regionalWeatherDataMapper.selectByOrgCodeAndDataTime(districtCode, DB_DATETIME_STR.format(row.getStartTime()));
|
||||
regionalWeatherDataMapper.selectByOrgCodeAndDataTime(districtCode,
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00:00").format(row.getStartTime()));
|
||||
|
||||
// 3.4 组装分时停电事件实体
|
||||
for (RegionalWeatherData regionalWeatherData : regionalWeatherDataList) {
|
||||
@ -122,8 +139,9 @@ public class HourlyOutageExcelProcessService {
|
||||
|
||||
/**
|
||||
* 累加已存在实体的字段
|
||||
*
|
||||
* @param existing 已存在的实体
|
||||
* @param row 当前 Excel 行数据
|
||||
* @param row 当前 Excel 行数据
|
||||
*/
|
||||
private void accumulateEvent(DnerHourlyPowerOutageEvent existing, DataExcelEntity row) {
|
||||
existing.setUserCount(row.getUserCount() + existing.getUserCount());
|
||||
@ -131,7 +149,8 @@ public class HourlyOutageExcelProcessService {
|
||||
|
||||
/**
|
||||
* 加载南网区划配置
|
||||
* **/
|
||||
*
|
||||
**/
|
||||
private void loadNwAreaConfig() {
|
||||
nwAreaMap.clear();
|
||||
List<NwSiteAreaConfiguration> list = nwSiteAreaConfigurationMapper.selectAll();
|
||||
@ -147,7 +166,8 @@ public class HourlyOutageExcelProcessService {
|
||||
|
||||
/**
|
||||
* 加载气象区划配置表
|
||||
* **/
|
||||
*
|
||||
**/
|
||||
private void loadWeatherAreaConfig() {
|
||||
weatherAreaMap.clear();
|
||||
List<WeatherSiteAreaConfiguration> list = weatherSiteAreaConfigurationMapper.selectAll();
|
||||
@ -190,8 +210,28 @@ public class HourlyOutageExcelProcessService {
|
||||
|
||||
// Excel 本身的业务字段
|
||||
event.setUserCount(row.getUserCount());
|
||||
event.setOutageState(row.getOutageState());
|
||||
event.setOutageType(row.getOutageType());
|
||||
|
||||
// 停电状态映射(1-待停电;2-停电中;3-已复电)
|
||||
String outageStateStr = row.getOutageState();
|
||||
if ("待停电".equals(outageStateStr)) {
|
||||
event.setOutageState("1");
|
||||
} else if ("停电中".equals(outageStateStr)) {
|
||||
event.setOutageState("2");
|
||||
} else if ("已复电".equals(outageStateStr)) {
|
||||
event.setOutageState("3");
|
||||
} else {
|
||||
event.setOutageState(outageStateStr); // 保留原值或根据需要设置默认值
|
||||
}
|
||||
|
||||
// 停电类型映射(1-故障类;2-计划类)
|
||||
String outageTypeStr = row.getOutageType();
|
||||
if ("故障类".equals(outageTypeStr)) {
|
||||
event.setOutageType("1");
|
||||
} else if ("计划类".equals(outageTypeStr)) {
|
||||
event.setOutageType("2");
|
||||
} else {
|
||||
event.setOutageType(outageTypeStr); // 保留原值或根据需要设置默认值
|
||||
}
|
||||
|
||||
// 气象字段(如不存在数据可以为 null)
|
||||
if (regionalWeatherData != null) {
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
package com.southern.power.grid.task;
|
||||
|
||||
import com.southern.power.grid.service.IDnerHourlyPowerOutageEventService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 停电开始时间超过7天自动归为已复电
|
||||
*
|
||||
* @author fsyud
|
||||
* {@code @date} 2026/03/20
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class OutageStateSetScheduledTask {
|
||||
|
||||
@Resource
|
||||
private IDnerHourlyPowerOutageEventService hourlyPowerOutageEventService;
|
||||
|
||||
/* @PostConstruct
|
||||
public void init() {
|
||||
hourlyPowerOutageEventService.setResumedScheduledTask();
|
||||
}*/
|
||||
|
||||
//@Scheduled(cron = "0 0 0 * * ?")
|
||||
public void schedule() {
|
||||
log.info("【设置已复电状态任务】定时触发--开始");
|
||||
try {
|
||||
hourlyPowerOutageEventService.setResumedScheduledTask();
|
||||
log.info("【设置已复电状态任务】定时触发--结束");
|
||||
} catch (Exception e) {
|
||||
log.error("【设置已复电状态任务】执行异常", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -63,4 +63,34 @@
|
||||
and data_time <![CDATA[ >= ]]> #{startDate}
|
||||
and data_time <![CDATA[ <= ]]> #{endDate}
|
||||
</select>
|
||||
|
||||
<!--
|
||||
查询 outageState=2 的数据,按 org_code + DATE(data_time) 分组,
|
||||
取每组最小 data_time,若早于 beforeTime(当前时间-7天)则返回该分组。
|
||||
只返回 orgCode+日期字符串,不拉取业务数据,避免大量数据进入内存。
|
||||
-->
|
||||
<select id="selectExpiredDateGroups" resultType="java.util.Map">
|
||||
SELECT org_code AS orgCode, DATE(data_time) AS dateGroup
|
||||
FROM dner_hourly_power_outage_event
|
||||
WHERE outage_state = '2'
|
||||
GROUP BY org_code, DATE(data_time)
|
||||
HAVING MIN(data_time) <![CDATA[ < ]]> #{beforeTime}
|
||||
</select>
|
||||
|
||||
<!--
|
||||
按 orgCode+日期分组批量更新 outageState 为 3,全部在 DB 层完成。
|
||||
使用 OR 拼接每个 (org_code, DATE(data_time)) 组合条件。
|
||||
-->
|
||||
<update id="batchUpdateOutageStateByGroups">
|
||||
UPDATE dner_hourly_power_outage_event
|
||||
SET outage_state = '3',
|
||||
update_time = NOW()
|
||||
WHERE outage_state = '2'
|
||||
AND (
|
||||
<foreach collection="groups" item="g" separator=" OR ">
|
||||
(org_code = #{g.orgCode} AND DATE(data_time) = #{g.dateGroup})
|
||||
</foreach>
|
||||
)
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
@ -115,8 +115,8 @@ CREATE TABLE `dner_hourly_power_outage_event`
|
||||
`extreme_wind_speed_hourly` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '小时内极大风速',
|
||||
`power_outage_duration` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '停电时长',
|
||||
`user_count` int(11) DEFAULT NULL COMMENT '停电影响用户总数',
|
||||
`restored_user_count` int(11) DEFAULT NULL COMMENT '已复电停电影响用户数',
|
||||
`not_restored_user_count` int(11) DEFAULT NULL COMMENT '未复电停电影响用户数',
|
||||
`restored_user_count` int(11) DEFAULT NULL COMMENT '已复电停电影响用户数',
|
||||
`not_restored_user_count` int(11) DEFAULT NULL COMMENT '未复电停电影响用户数',
|
||||
`fault_user_count` int(11) DEFAULT NULL COMMENT '故障停电影响用户总数',
|
||||
`scheduled_user_count` int(11) DEFAULT NULL COMMENT '计划停电影响用户数',
|
||||
`outage_state` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '停电状态(1-待停电;2-停电中;3-已复电)',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user