From c7cbf45c2dcd4d0cb3f832d4dc94de62ca5e7be6 Mon Sep 17 00:00:00 2001 From: yufengshuo Date: Tue, 24 Mar 2026 18:00:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=81=9C=E7=94=B5=E5=BC=80=E5=A7=8B=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E8=B6=85=E8=BF=877=E5=A4=A9=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=BD=92=E4=B8=BA=E5=B7=B2=E5=A4=8D=E7=94=B5=20=EF=BC=9B?= =?UTF-8?q?=E5=81=9C=E7=94=B5=E5=88=86=E6=97=B6=E3=80=81=E6=97=A5K?= =?UTF-8?q?=E5=9B=BE=E3=80=81=E6=97=A5=E7=B4=AF=E8=AE=A1=E5=81=9C=E7=94=B5?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E9=9C=80=E6=8C=89=E5=81=9C=E7=94=B5=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=8B=86=E5=88=86=E6=95=85=E9=9A=9C=E5=81=9C=E7=94=B5?= =?UTF-8?q?=E3=80=81=E8=AE=A1=E5=88=92=E5=81=9C=E7=94=B5=E3=80=81=E5=85=A8?= =?UTF-8?q?=E9=83=A8(20%)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/DnerHourlyPowerOutageEventMapper.java | 18 +++++ .../entity/DnerDailyPowerOutageEvent.java | 10 +++ .../IDnerHourlyPowerOutageEventService.java | 7 ++ ...DnerDailyPowerOutageEventBatchService.java | 4 ++ ...DnerHourlyPowerOutageEventServiceImpl.java | 58 ++++++++++++++-- .../impl/HourlyOutageExcelProcessService.java | 68 +++++++++++++++---- .../task/OutageStateSetScheduledTask.java | 38 +++++++++++ .../DnerHourlyPowerOutageEventMapper.xml | 30 ++++++++ src/main/resources/sql/20260313-001.sql | 4 +- 9 files changed, 217 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/southern/power/grid/task/OutageStateSetScheduledTask.java diff --git a/src/main/java/com/southern/power/grid/dao/DnerHourlyPowerOutageEventMapper.java b/src/main/java/com/southern/power/grid/dao/DnerHourlyPowerOutageEventMapper.java index 950a4a8..630a129 100644 --- a/src/main/java/com/southern/power/grid/dao/DnerHourlyPowerOutageEventMapper.java +++ b/src/main/java/com/southern/power/grid/dao/DnerHourlyPowerOutageEventMapper.java @@ -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 selectByOrgCodesAndDataTime(@Param("orgCodes") List 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> selectExpiredDateGroups(@Param("beforeTime") String beforeTime); + + /** + * 按 orgCode+日期分组批量将 outageState 更新为 3 + * + * @param groups orgCode+dateGroup 组合列表 + * @return 更新行数 + */ + int batchUpdateOutageStateByGroups(@Param("groups") List> groups); } diff --git a/src/main/java/com/southern/power/grid/entity/DnerDailyPowerOutageEvent.java b/src/main/java/com/southern/power/grid/entity/DnerDailyPowerOutageEvent.java index 4e7f97c..e6cfae2 100644 --- a/src/main/java/com/southern/power/grid/entity/DnerDailyPowerOutageEvent.java +++ b/src/main/java/com/southern/power/grid/entity/DnerDailyPowerOutageEvent.java @@ -103,6 +103,16 @@ public class DnerDailyPowerOutageEvent { */ private Integer scheduledUserCount; + /** + * 已复电停电影响用户数 + */ + private Integer restoredUserCount; + + /** + * 未复电停电影响用户数 + */ + private Integer notRestoredUserCount; + /** * 停电状态(1-待停电;2-停电中;3-已复电) */ diff --git a/src/main/java/com/southern/power/grid/service/IDnerHourlyPowerOutageEventService.java b/src/main/java/com/southern/power/grid/service/IDnerHourlyPowerOutageEventService.java index 425134e..bc007c1 100644 --- a/src/main/java/com/southern/power/grid/service/IDnerHourlyPowerOutageEventService.java +++ b/src/main/java/com/southern/power/grid/service/IDnerHourlyPowerOutageEventService.java @@ -20,4 +20,11 @@ public interface IDnerHourlyPowerOutageEventService extends IService 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); diff --git a/src/main/java/com/southern/power/grid/service/impl/DnerHourlyPowerOutageEventServiceImpl.java b/src/main/java/com/southern/power/grid/service/impl/DnerHourlyPowerOutageEventServiceImpl.java index 8a4c536..5d2397e 100644 --- a/src/main/java/com/southern/power/grid/service/impl/DnerHourlyPowerOutageEventServiceImpl.java +++ b/src/main/java/com/southern/power/grid/service/impl/DnerHourlyPowerOutageEventServiceImpl.java @@ -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 @@ -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> expiredGroups = + dnerHourlyPowerOutageEventMapper.selectExpiredDateGroups(beforeTime); + + if (expiredGroups == null || expiredGroups.isEmpty()) { + log.info("[setResumedScheduledTask] 无超期停电数据,跳过更新"); + return; + } + + // 转换为 Map 供 XML foreach 使用 + List> groups = expiredGroups.stream().map(m -> { + Map 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> 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); + } + } diff --git a/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java b/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java index 6878bc3..1e6fb2a 100644 --- a/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java +++ b/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java @@ -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 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 list = nwSiteAreaConfigurationMapper.selectAll(); @@ -147,7 +166,8 @@ public class HourlyOutageExcelProcessService { /** * 加载气象区划配置表 - * **/ + * + **/ private void loadWeatherAreaConfig() { weatherAreaMap.clear(); List 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) { diff --git a/src/main/java/com/southern/power/grid/task/OutageStateSetScheduledTask.java b/src/main/java/com/southern/power/grid/task/OutageStateSetScheduledTask.java new file mode 100644 index 0000000..668637e --- /dev/null +++ b/src/main/java/com/southern/power/grid/task/OutageStateSetScheduledTask.java @@ -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); + } + } +} diff --git a/src/main/resources/mapper/DnerHourlyPowerOutageEventMapper.xml b/src/main/resources/mapper/DnerHourlyPowerOutageEventMapper.xml index 49c5f88..c27d741 100644 --- a/src/main/resources/mapper/DnerHourlyPowerOutageEventMapper.xml +++ b/src/main/resources/mapper/DnerHourlyPowerOutageEventMapper.xml @@ -63,4 +63,34 @@ and data_time = ]]> #{startDate} and data_time #{endDate} + + + + + + + UPDATE dner_hourly_power_outage_event + SET outage_state = '3', + update_time = NOW() + WHERE outage_state = '2' + AND ( + + (org_code = #{g.orgCode} AND DATE(data_time) = #{g.dateGroup}) + + ) + + diff --git a/src/main/resources/sql/20260313-001.sql b/src/main/resources/sql/20260313-001.sql index 4e1c799..5ad6587 100644 --- a/src/main/resources/sql/20260313-001.sql +++ b/src/main/resources/sql/20260313-001.sql @@ -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-已复电)',