diff --git a/backend/src/main/java/com/yfd/platform/config/JobRunner.java b/backend/src/main/java/com/yfd/platform/config/JobRunner.java index 74bf8dbd..f6d180e5 100644 --- a/backend/src/main/java/com/yfd/platform/config/JobRunner.java +++ b/backend/src/main/java/com/yfd/platform/config/JobRunner.java @@ -15,7 +15,14 @@ */ package com.yfd.platform.config; +import cn.hutool.core.date.DateField; +import cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.yfd.platform.qgc_env.wq.entity.ao.JobBaseAo; +import com.yfd.platform.qgc_env.wq.service.EnvWqDataService; +import com.yfd.platform.qgc_job.service.IDwJobService; +import com.yfd.platform.qgc_job.service.IEqJobService; +import com.yfd.platform.qgc_job.service.IFhJobService; import com.yfd.platform.system.domain.QuartzJob; import com.yfd.platform.system.mapper.QuartzJobMapper; import com.yfd.platform.utils.QuartzManage; @@ -42,6 +49,10 @@ public class JobRunner implements ApplicationRunner { private static final Logger log = LoggerFactory.getLogger(JobRunner.class); private final QuartzJobMapper quartzJobMapper; private final QuartzManage quartzManage; + private final EnvWqDataService envWqDataService; + private final IEqJobService eqJobService; + private final IDwJobService dwJobService; + private final IFhJobService fhJobService; /** * 项目启动时重新激活启用的定时任务 @@ -55,5 +66,25 @@ public class JobRunner implements ApplicationRunner { quartzJobMapper.selectList(new LambdaQueryWrapper().eq(QuartzJob::getStatus, "1")); quartzJobs.forEach(quartzManage::addJob); log.info("--------------------定时任务注入完成---------------------"); + JobBaseAo ao = new JobBaseAo(); + //如果没有传递时间,则默认为上个月的开始到现在 + if (null == ao.getEndTime()){ + ao.setEndTime(DateUtil.date()); + } + if (null == ao.getStartTime()){ + ao.setStartTime(DateUtil.beginOfYear(DateUtil.offset(ao.getEndTime(), DateField.YEAR,-1))); + } + envWqDataService.wqLastData(ao); + log.info("--------------------wq最新一条数据---------------------"); + eqJobService.eqAnchorPointLastDate(ao); + log.info("--------------------eq最新一条数据---------------------"); + eqJobService.eqAnchorPointLastDate(ao); + log.info("--------------------eq最新一条数据---------------------"); + dwJobService.wtLastData(ao); + log.info("--------------------wt最新一条数据---------------------"); + dwJobService.wtvtPointData(ao); + log.info("--------------------wt最新一条数据---------------------"); + fhJobService.zqLastData(ao); + log.info("--------------------fh最新一条数据---------------------"); } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/domain/vo/EngPointVo.java b/backend/src/main/java/com/yfd/platform/qgc_base/domain/vo/EngPointVo.java index c693d44d..ad4444c9 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/domain/vo/EngPointVo.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/domain/vo/EngPointVo.java @@ -1,5 +1,6 @@ package com.yfd.platform.qgc_base.domain.vo; +import com.yfd.platform.qgc_eng.eq.entity.vo.LastTmEngEqDataVo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -99,4 +100,7 @@ public class EngPointVo { @Schema(description = "基地排序") private Integer baseStepSort; + + @Schema(description="电站最新数据:入库流量和出库流量") + private LastTmEngEqDataVo lastTmEngEqDataVo; } \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdEngInfoBHServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdEngInfoBHServiceImpl.java index 45447ad9..d37e12a3 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdEngInfoBHServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdEngInfoBHServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -42,8 +43,10 @@ import com.yfd.platform.qgc_base.mapper.SdEngInfoBHMapper; import com.yfd.platform.qgc_base.service.IDataScopeFilterService; import com.yfd.platform.qgc_base.service.IMsOperationLogService; import com.yfd.platform.qgc_base.service.ISdEngInfoBHService; +import com.yfd.platform.qgc_eng.eq.entity.vo.LastTmEngEqDataVo; import com.yfd.platform.system.service.IAdminAuthService; import com.yfd.platform.utils.QgcQueryWrapperUtil; +import com.yfd.platform.utils.RedisCacheUtil; import com.yfd.platform.utils.SecurityUtils; import jakarta.annotation.Resource; import org.springframework.cache.annotation.CacheEvict; @@ -65,7 +68,8 @@ import java.util.stream.Collectors; public class SdEngInfoBHServiceImpl extends ServiceImpl implements ISdEngInfoBHService { private static final Map ENG_CODE_NAME_FIELD_MAP = new LinkedHashMap<>(); - + @Resource + private RedisCacheUtil redisCacheUtil; @Resource private IDataScopeFilterService dataScopeFilterService; @@ -1009,6 +1013,18 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl stInfoMap = microservicDynamicSQLMapper.getOneBySql(buildStcdInfoViewSql(), Collections.singletonMap("stcd", stcd)); + if (stInfoMap != null && !stInfoMap.isEmpty()) { + EngStInfoResultVo result = new EngStInfoResultVo(); + result.setMsStbprpT(buildCamelCaseMsStbprpTMap(stInfoMap)); + result.setStBaseInfo(buildStBaseInfo(stInfoMap)); + return result; + } + EngBaseInfoVo baseInfo = getStInfoByStcd(stcd); if (baseInfo == null) { return null; @@ -1035,6 +1051,138 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl stInfoMap) { + EngStBaseInfoVo stBaseInfo = new EngStBaseInfoVo(); + stBaseInfo.setStcd(getMapString(stInfoMap, "stcd")); + stBaseInfo.setStnm(getMapString(stInfoMap, "stnm")); + stBaseInfo.setSttpCode(getMapString(stInfoMap, "sttpCode")); + stBaseInfo.setSttpName(getMapString(stInfoMap, "sttpName")); + stBaseInfo.setSttpFullPath(getMapString(stInfoMap, "sttpFullPath")); + stBaseInfo.setSttpTreeLevel(getMapInteger(stInfoMap, "sttpTreeLevel")); + stBaseInfo.setStCode(null); + stBaseInfo.setStName(null); + stBaseInfo.setBaseId(getMapString(stInfoMap, "baseId")); + stBaseInfo.setBaseName(getMapString(stInfoMap, "baseName")); + stBaseInfo.setHbrvcd(getMapString(stInfoMap, "hbrvcd")); + stBaseInfo.setHbrvcdName(getMapString(stInfoMap, "hbrvcdName")); + stBaseInfo.setRvcd(getMapString(stInfoMap, "rvcd")); + stBaseInfo.setRvcdName(getMapString(stInfoMap, "rvcdName")); + return stBaseInfo; + } + + private Map buildCamelCaseMsStbprpTMap(Map stInfoMap) { + LinkedHashMap result = new LinkedHashMap<>(); + List canonicalKeys = Arrays.asList( + "stcd", "stnm","ennm", "sttp", "sttpCode", "sttpName", "sttpFullPath", "sttpTreeLevel", + "rstcd", "baseId", "baseName", "hbrvcd", "hbrvcdName", "rvcd", "rvcdName", "addvcd","addvcdName","hycd","hynm","topHycd","topHynm", + "lgtd", "lttd", "stlc", "usfl", "dtin", "dtinTm", "bldsttCode", "introduce", "logo", + "inffile","bldsttCcodeName", "inv", "invinmn", "stdsdt", "pststdt", "pesstdt", "swdt", "jcdt", "wddt", + "orderIndex", "remark", "vlsr", "vlsrTm", "recordUser", "recordTime", "modifyUser", + "modifyTime", "isDeleted", "deleteUser", "deleteTime", "dataSource" + ); + for (String canonicalKey : canonicalKeys) { + result.put(canonicalKey, getMapValue(stInfoMap, canonicalKey)); + } + return result; + } + + private String getMapString(Map source, String key) { + Object value = getMapValue(source, key); + return value == null ? null : String.valueOf(value); + } + + private Integer getMapInteger(Map source, String key) { + Object value = getMapValue(source, key); + if (value == null) { + return null; + } + if (value instanceof Number number) { + return number.intValue(); + } + return Integer.parseInt(String.valueOf(value)); + } + + private Object getMapValue(Map source, String key) { + if (source == null || source.isEmpty() || StrUtil.isBlank(key)) { + return null; + } + if (source.containsKey(key)) { + return source.get(key); + } + String upperKey = key.toUpperCase(Locale.ROOT); + if (source.containsKey(upperKey)) { + return source.get(upperKey); + } + String lowerKey = key.toLowerCase(Locale.ROOT); + if (source.containsKey(lowerKey)) { + return source.get(lowerKey); + } + for (Map.Entry entry : source.entrySet()) { + if (entry.getKey() != null && entry.getKey().equalsIgnoreCase(key)) { + return entry.getValue(); + } + } + return null; + } + private String buildVmsstbprptViewSql() { return "SELECT " + "eng.STCD AS id, " + @@ -2713,9 +2861,9 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); List list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, EngPointVo.class); - + if(CollUtil.isNotEmpty(list)){ + for( EngPointVo engPointVo: list ){ + String stcd = engPointVo.getStcd(); + //查询最新一条数据的缓存 + LastTmEngEqDataVo lastTmEngEqDataVo = redisCacheUtil.fromJson(redisCacheUtil.getString("eqAnchorPointLastDate:"+stcd),LastTmEngEqDataVo.class); + if (ObjectUtil.isEmpty(lastTmEngEqDataVo)){ + lastTmEngEqDataVo = new LastTmEngEqDataVo(); + lastTmEngEqDataVo.setStcd(engPointVo.getStcd()); + }else{ + lastTmEngEqDataVo.setStcd(engPointVo.getStcd()); + } + // 设置电站名称、装机容量、正常蓄水位 + lastTmEngEqDataVo.setStnm(engPointVo.getEnnm()); + lastTmEngEqDataVo.setTtpwr(engPointVo.getTtpwr()); + lastTmEngEqDataVo.setNormz(engPointVo.getNormz()); + engPointVo.setLastTmEngEqDataVo(lastTmEngEqDataVo); + } + } result.setData(list); result.setTotal(page == null ? list.size() : page.getTotal()); return result; diff --git a/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/impl/EngEqDataServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/impl/EngEqDataServiceImpl.java index 53472205..b1801412 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/impl/EngEqDataServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/impl/EngEqDataServiceImpl.java @@ -37,6 +37,7 @@ import com.yfd.platform.qgc_eng.eq.entity.vo.WbsbVo; import com.yfd.platform.qgc_eng.eq.entity.vo.StBaseInfo; import com.yfd.platform.qgc_eng.eq.entity.vo.StcdInfoVo; import com.yfd.platform.qgc_eng.eq.service.EngEqDataService; +import com.yfd.platform.qgc_env.wq.entity.vo.MsWarnRuleDetailBVo; import com.yfd.platform.qgc_env.wt.utils.SiteAvoidanceUtils; import com.yfd.platform.utils.QgcQueryWrapperUtil; import jakarta.annotation.Resource; @@ -6000,6 +6001,20 @@ public class EngEqDataServiceImpl implements EngEqDataService { resultList.add(eqdsVo); } + Map qecLimitQueryMap = new LinkedHashMap<>(); + Date currentDate = new Date(); + for (EngEqdsVo eqdsVo : resultList) { + if (eqdsVo == null || StrUtil.isBlank(eqdsVo.getRstcd()) || qecLimitQueryMap.containsKey(eqdsVo.getRstcd())) { + continue; + } + qecLimitQueryMap.put(eqdsVo.getRstcd(), currentDate); + } + Map qecLimitMap = getQecLimitMap(qecLimitQueryMap); + for (EngEqdsVo eqdsVo : resultList) { + MsWarnRuleDetailBVo ruleDetail = qecLimitMap.get(eqdsVo.getRstcd()); + eqdsVo.setQecLimit(ruleDetail == null ? null : ruleDetail.getMinVal()); + } + SiteAvoidanceUtils.calcSiteMapLev(resultList, EngEqdsVo::getStcd, EngEqdsVo::getLgtd, @@ -6011,4 +6026,152 @@ public class EngEqDataServiceImpl implements EngEqDataService { dataSourceResult.setTotal(page == null ? resultList.size() : page.getTotal()); return dataSourceResult; } + + private Map getQecLimitMap(Map stcdTmMap) { + Map resultMap = new HashMap<>(); + if (stcdTmMap == null || stcdTmMap.isEmpty()) { + return resultMap; + } + + Map paramMap = new HashMap<>(); + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append("rel.STCD AS stcd, ") + .append("det.ID AS id, ") + .append("det.RULE_ID AS ruleId, ") + .append("det.TB_ID AS tbId, ") + .append("det.YS AS ys, ") + .append("det.TM AS tm, ") + .append("det.BEGIN_TIME AS beginTime, ") + .append("det.END_TIME AS endTime, ") + .append("det.MIN_VAL AS minVal, ") + .append("det.MAX_VAL AS maxVal, ") + .append("det.VLSR AS vlsr, ") + .append("det.VLSR_TM AS vlsrTm ") + .append("FROM MS_WARN_RULE_STBPRP_B rel ") + .append("INNER JOIN MS_WARN_RULE_B rule ON rule.ID = rel.RULE_ID ") + .append(" AND rule.RULE_TYPE = 'EQMN' ") + .append(" AND NVL(rule.IS_DELETED, 0) = 0 ") + .append("INNER JOIN MS_WARN_RULE_DETAIL_B det ON det.RULE_ID = rule.ID ") + .append(" AND det.YS = 'QEC' ") + .append(" AND NVL(det.IS_DELETED, 0) = 0 ") + .append("INNER JOIN ST_TB_B tb ON tb.ID = det.TB_ID ") + .append(" AND tb.TB_CODE = 'QEC_R' ") + .append(" AND NVL(tb.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(rel.IS_DELETED, 0) = 0 "); + appendInCondition(sql, paramMap, "rel.STCD", stcdTmMap.keySet(), "qecLimitStcd"); + sql.append("ORDER BY rel.STCD, det.TM DESC, LPAD(det.BEGIN_TIME, 4, '0') DESC NULLS LAST, ") + .append("LPAD(det.END_TIME, 4, '0') DESC NULLS LAST"); + + List> ruleRows = microservicDynamicSQLMapper.pageAllList(null, sql.toString(), paramMap); + if (CollUtil.isEmpty(ruleRows)) { + return resultMap; + } + + Map> groupedRuleMap = new HashMap<>(); + for (Map row : ruleRows) { + String stcd = asString(row.get("STCD")); + if (StrUtil.isBlank(stcd)) { + continue; + } + groupedRuleMap.computeIfAbsent(stcd, key -> new ArrayList<>()).add(toMsWarnRuleDetailBVo(row)); + } + + for (Map.Entry entry : stcdTmMap.entrySet()) { + MsWarnRuleDetailBVo detail = resolveQecLimitDetail(entry.getValue(), groupedRuleMap.get(entry.getKey())); + if (detail != null) { + resultMap.put(entry.getKey(), detail); + } + } + return resultMap; + } + + private MsWarnRuleDetailBVo resolveQecLimitDetail(Date queryDate, List ruleRows) { + if (queryDate == null || CollUtil.isEmpty(ruleRows)) { + return null; + } + Date currentTm = null; + List currentRows = new ArrayList<>(); + String monthDay = DateTimeFormatter.ofPattern("MMdd").format( + queryDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() + ); + for (MsWarnRuleDetailBVo row : ruleRows) { + Date tm = row.getTm(); + if (tm == null || queryDate.compareTo(tm) < 0) { + continue; + } + if (currentTm != null && !currentTm.equals(tm)) { + return matchQecLimitDetail(monthDay, currentRows); + } + currentTm = tm; + currentRows.add(row); + } + if (currentTm == null) { + return null; + } + return matchQecLimitDetail(monthDay, currentRows); + } + + private MsWarnRuleDetailBVo matchQecLimitDetail(String monthDay, List ruleRows) { + MsWarnRuleDetailBVo defaultValue = null; + for (MsWarnRuleDetailBVo row : ruleRows) { + if (row == null || row.getMinVal() == null) { + continue; + } + String beginTime = normalizeMonthDay(row.getBeginTime()); + String endTime = normalizeMonthDay(row.getEndTime()); + if (StrUtil.isNotBlank(beginTime) && StrUtil.isNotBlank(endTime)) { + if (isMonthDayInRange(monthDay, beginTime, endTime)) { + return row; + } + continue; + } + if (StrUtil.isBlank(beginTime) && StrUtil.isBlank(endTime)) { + defaultValue = row; + } + } + return defaultValue; + } + + private MsWarnRuleDetailBVo toMsWarnRuleDetailBVo(Map row) { + MsWarnRuleDetailBVo vo = new MsWarnRuleDetailBVo(); + vo.setId(asString(row.get("ID"))); + vo.setRuleId(asString(row.get("RULEID"))); + vo.setTbId(asString(row.get("TBID"))); + vo.setYs(asString(row.get("YS"))); + vo.setTm(toDate(row.get("TM"))); + vo.setBeginTime(asString(row.get("BEGINTIME"))); + vo.setEndTime(asString(row.get("ENDTIME"))); + vo.setMinVal(toBigDecimal(row.get("MINVAL"))); + vo.setMaxVal(toBigDecimal(row.get("MAXVAL"))); + vo.setVlsr(asString(row.get("VLSR"))); + vo.setVlsrTm(toDate(row.get("VLSRTM"))); + return vo; + } + + private void appendInCondition(StringBuilder sql, + Map paramMap, + String column, + Iterable values, + String prefix) { + if (values == null) { + return; + } + List placeholders = new ArrayList<>(); + int index = 0; + for (String value : values) { + if (StrUtil.isBlank(value)) { + continue; + } + String key = prefix + index++; + paramMap.put(key, value.trim()); + placeholders.add("#{map." + key + "}"); + } + if (CollUtil.isEmpty(placeholders)) { + return; + } + sql.append(" AND ").append(column).append(" IN (") + .append(String.join(", ", placeholders)) + .append(") "); + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java index 98201b27..af960fd2 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java @@ -4626,7 +4626,7 @@ public class FbStationServiceImpl implements FbStationService { .append("a.RSTCD AS rstcds, ") .append("a.BASE_ID AS baseId, ") .append("a.DTIN AS dtin, ") - .append("eng.ENNM AS ennm, ") + .append("COALESCE(eng.ENNM, '') AS ennm, ") .append("eng.RVCD AS rvcd, ") .append("eng.ADDVCD AS addvcd, ") .append("NVL(siteSort.SORT, 999999) AS siteStepSort, ") diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/impl/WarnDataServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/impl/WarnDataServiceImpl.java index 01cd74b5..1ec35350 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/impl/WarnDataServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/impl/WarnDataServiceImpl.java @@ -22,6 +22,7 @@ import com.yfd.platform.qgc_env.warn.entity.vo.StcdWarnStateVo; import com.yfd.platform.qgc_env.warn.service.WarnDataService; import com.yfd.platform.utils.QgcQueryWrapperUtil; import jakarta.annotation.Resource; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.math.BigDecimal; @@ -260,6 +261,7 @@ public class WarnDataServiceImpl implements WarnDataService { } @Override + @Cacheable(cacheNames = "warn#3600", keyGenerator = "cacheKeyGenerator") public DataSourceResult getAlarmPointKendoListCust(DataSourceRequest dataSourceRequest) { DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); String startTimeText = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "startTime"); diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/SdWqR.java b/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/SdWqR.java new file mode 100644 index 00000000..673d1656 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/SdWqR.java @@ -0,0 +1,310 @@ +package com.yfd.platform.qgc_env.wq.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@TableName("SD_WQ_R") +@Schema(description = "水质监测数据表实体") +public class SdWqR { + + @TableId(value = "ID", type = IdType.ASSIGN_UUID) + @Schema(description = "主键") + private String id; + + @TableField("STCD") + @Schema(description = "站码") + private String stcd; + + @TableField("TM") + @Schema(description = "采样时间") + private Date tm; + + @TableField("WQGRD") + @Schema(description = "水质类别") + private String wqgrd; + + + @Schema(description = "水质类别") + @TableField(exist = false) + private String wqgrdName; + + @TableField("PERIOD") + @Schema(description = "丰平枯时期") + private String period; + + @TableField("SPSTLC") + @Schema(description = "水平位置") + private Long spstlc; + + @TableField("WTMP") + @Schema(description = "水温") + private BigDecimal wtmp; + + @TableField("PH") + @Schema(description = "PH") + private BigDecimal ph; + + @TableField("DOX") + @Schema(description = "溶解氧") + private BigDecimal dox; + + @TableField("CODMN") + @Schema(description = "高锰酸盐指数") + private BigDecimal codmn; + + @TableField("CODCR") + @Schema(description = "化学需氧量") + private BigDecimal codcr; + + @TableField("BOD5") + @Schema(description = "五日生化需氧量") + private BigDecimal bod5; + + @TableField("NH3N") + @Schema(description = "氨氮") + private BigDecimal nh3n; + + @TableField("TP") + @Schema(description = "总磷") + private BigDecimal tp; + + @TableField("TN") + @Schema(description = "总氮") + private BigDecimal tn; + + @TableField("CU") + @Schema(description = "铜") + private BigDecimal cu; + + @TableField("ZN") + @Schema(description = "锌") + private BigDecimal zn; + + @TableField("F") + @Schema(description = "氟化物") + private BigDecimal f; + + @TableField("SE") + @Schema(description = "硒") + private BigDecimal se; + + @TableField("ARS") + @Schema(description = "砷") + private BigDecimal ars; + + @TableField("HG") + @Schema(description = "汞") + private BigDecimal hg; + + @TableField("CD") + @Schema(description = "镉") + private BigDecimal cd; + + @TableField("CR6") + @Schema(description = "铬(六价)") + private BigDecimal cr6; + + @TableField("PB") + @Schema(description = "铅") + private BigDecimal pb; + + @TableField("CN") + @Schema(description = "氰化物") + private BigDecimal cn; + + @TableField("VLPH") + @Schema(description = "挥发酚") + private BigDecimal vlph; + + @TableField("OIL") + @Schema(description = "石油类") + private BigDecimal oil; + + @TableField("LAS") + @Schema(description = "阴离子表面活性剂") + private BigDecimal las; + + @TableField("S2") + @Schema(description = "硫化物") + private BigDecimal s2; + + @TableField("FCG") + @Schema(description = "粪大肠菌群") + private BigDecimal fcg; + + @TableField("CL") + @Schema(description = "氯化物") + private BigDecimal cl; + + @TableField("SO4") + @Schema(description = "硫酸盐") + private BigDecimal so4; + + @TableField("NO3") + @Schema(description = "硝氮/硝酸盐氮") + private BigDecimal no3; + + @TableField("THRD") + @Schema(description = "总硬度") + private BigDecimal thrd; + + @TableField("COND") + @Schema(description = "电导率") + private BigDecimal cond; + + @TableField("FE") + @Schema(description = "铁") + private BigDecimal fe; + + @TableField("MN") + @Schema(description = "锰") + private BigDecimal mn; + + @TableField("AL") + @Schema(description = "铝") + private BigDecimal al; + + @TableField("CHLA") + @Schema(description = "叶绿素a") + private BigDecimal chla; + + @TableField("CLARITY") + @Schema(description = "透明度") + private BigDecimal clarity; + + @TableField("TU") + @Schema(description = "浊度") + private BigDecimal tu; + + @TableField("CYANO") + @Schema(description = "蓝绿藻") + private BigDecimal cyano; + + @TableField("NI") + @Schema(description = "镍") + private BigDecimal ni; + + @TableField("TOD") + @Schema(description = "总氧/总需氧量") + private BigDecimal tod; + + @TableField("SFDB") + @Schema(description = "是否达标") + private Integer sfdb; + + @TableField("FID") + @Schema(description = "文件ID") + private String fid; + + @TableField("VLSR") + @Schema(description = "数据来源") + private String vlsr; + + @TableField("WQ_SFDBHN_YS") + @Schema(description = "水质不达标的要素") + private String wqSfdbhnYs; + + @TableField("REMARK") + @Schema(description = "备注") + private String remark; + + @TableField("TLI_SUM") + @Schema(description = "综合营养状态指数") + private BigDecimal tliSum; + + @TableField("TLI_SUM_LEVEL") + @Schema(description = "综合营养状态指数分级") + private String tliSumLevel; + + @TableField("CA") + @Schema(description = "钙") + private BigDecimal ca; + + @TableField("PO4") + @Schema(description = "磷酸盐") + private BigDecimal po4; + + @TableField("N_NO2") + @Schema(description = "亚硝酸盐氮(弃用)") + private BigDecimal nNo2; + + @TableField("NA") + @Schema(description = "钠") + private BigDecimal na; + + @TableField("K") + @Schema(description = "钾") + private BigDecimal k; + + @TableField("TOC") + @Schema(description = "总有机碳") + private BigDecimal toc; + + @TableField("OPOR") + @Schema(description = "有机磷农药") + private BigDecimal opor; + + @TableField("SS") + @Schema(description = "悬浮物") + private BigDecimal ss; + + @TableField("NO2") + @Schema(description = "亚硝酸盐氮") + private BigDecimal no2; + + @TableField("ORP") + @Schema(description = "氧化还原电位") + private BigDecimal orp; + + @TableField("FWGHTEMP") + @Schema(description = "FWGHTEMP") + private BigDecimal fwghtemp; + + @TableField("RECORD_USER") + @Schema(description = "创建人") + private String recordUser; + + @TableField("RECORD_TIME") + @Schema(description = "创建时间") + private Date recordTime; + + @TableField("MODIFY_USER") + @Schema(description = "更新人") + private String modifyUser; + + @TableField("MODIFY_TIME") + @Schema(description = "更新时间") + private Date modifyTime; + + @TableField("IS_DELETED") + @Schema(description = "是否已删除") + private Integer isDeleted; + + @TableField("DELETE_USER") + @Schema(description = "删除人") + private String deleteUser; + + @TableField("DELETE_TIME") + @Schema(description = "删除时间") + private Date deleteTime; + + @TableField(exist = false) + private Integer sfdbNew; + + @TableField(exist = false) + private String tmNew; + + @TableField(exist = false) + private String baseId; + + @TableField(exist = false) + private Integer dtinType; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/ao/JobBaseAo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/ao/JobBaseAo.java new file mode 100644 index 00000000..0c2525af --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/ao/JobBaseAo.java @@ -0,0 +1,139 @@ +package com.yfd.platform.qgc_env.wq.entity.ao; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Calendar; +import java.util.Date; +import java.util.Set; + +@Data +@Schema(description = "定时任务基础参数") +public class JobBaseAo { + + public static final String JOB_TYPE_DAY = "day"; + public static final String JOB_TYPE_HOUR = "hour"; + + @Schema(description = "job类型 day=天 hour=小时", example = "hour", allowableValues = "day,hour") + private String jobType; + + @Schema(description = "只能是数字或特定字符串,为空=1。job类型为天即单位为天,类型为小时即单位小时 today=当天 am15=跨月15天取开始月份1号", example = "2") + private String jobStep; + + @Schema(description = "开始时间", example = "2022-08-01 00:00:00") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date startTime; + + @Schema(description = "结束时间", example = "2022-08-31 23:59:59") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date endTime; + + @Schema(description = "设施类型") + private String sttpCode; + + @Schema(description = "测站编码集合") + private Set stcds; + + @Schema(description = "备注") + private String remarks; + + public void initTime() { + Date startTime = this.getStartTime(); + Date endTime = this.getEndTime(); + if (startTime == null || endTime == null) { + Date now = new Date(); + String num = this.getJobStep() != null && !"".equals(this.getJobStep().trim()) ? this.getJobStep() : "1"; + if ("hour".equals(this.getJobType())) { + if ("today".equalsIgnoreCase(num)) { + startTime = getDayStartTime(now); + endTime = parseWholeMinuteEnd(now); + } else { + startTime = parseWholeMinuteStart(DateUtils.addHours(now, -Integer.parseInt(num))); + endTime = parseWholeMinuteEnd(now); + } + } else if ("day".equals(this.getJobType())) { + if ("today".equalsIgnoreCase(num)) { + startTime = getDayStartTime(now); + endTime = parseWholeMinuteEnd(now); + } else if (num.toLowerCase().startsWith("am")) { + num = num.replace("am", ""); + startTime = getMonthFirstDayStartTime(DateUtils.addDays(now, -Integer.parseInt(num))); + endTime = parseWholeMinuteEnd(now); + } else { + startTime = getDayStartTime(DateUtils.addDays(now, -Integer.parseInt(num))); + endTime = parseWholeMinuteEnd(now); + } + } + } + + if (startTime != null && endTime != null) { + if (startTime.getTime() > endTime.getTime()) { + throw new RuntimeException("开始时间不能大于结束时间"); + } else { + this.startTime = startTime; + this.endTime = endTime; + } + } else { + throw new RuntimeException("开始时间和结束时间不能为空"); + } + } + + private Date getMonthFirstDayStartTime(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + return calendar.getTime(); + } + + private static Date getDayStartTime(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + return calendar.getTime(); + } + + private static Date parseWholeMinuteEnd(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.set(Calendar.MINUTE, 59); + calendar.set(Calendar.SECOND, 59); + calendar.set(Calendar.MILLISECOND, 999); + return calendar.getTime(); + } + + private static Date parseWholeMinuteStart(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + return calendar.getTime(); + } + + private static class DateUtils { + public static Date addHours(Date date, int hours) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.add(Calendar.HOUR_OF_DAY, hours); + return calendar.getTime(); + } + + public static Date addDays(Date date, int days) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.add(Calendar.DAY_OF_MONTH, days); + return calendar.getTime(); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/vo/EnvWqDataVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/vo/EnvWqDataVo.java index c7c8cd5b..88101692 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/vo/EnvWqDataVo.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/vo/EnvWqDataVo.java @@ -1,5 +1,6 @@ package com.yfd.platform.qgc_env.wq.entity.vo; +import com.baomidou.mybatisplus.annotation.TableField; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -11,6 +12,8 @@ import java.util.Map; @Data @Schema(description = "水质实时数据") public class EnvWqDataVo { + @Schema(description = "id") + private String id; @Schema(description = "测站编码") private String stcd; @Schema(description = "电站编码") @@ -137,6 +140,34 @@ public class EnvWqDataVo { private Integer rstcdStepSort; @Schema(description = "测站排序") private Integer siteStepSort; + + @Schema(description = "创建人") + private String recordUser; + + + @Schema(description = "创建时间") + private Date recordTime; + + + @Schema(description = "更新人") + private String modifyUser; + + + @Schema(description = "更新时间") + private Date modifyTime; + + + @Schema(description = "是否已删除") + private Integer isDeleted; + + + @Schema(description = "删除人") + private String deleteUser; + + + @Schema(description = "删除时间") + private Date deleteTime; + @Schema(description = "水质要素最小限值集合") private List> min; @Schema(description = "水质要素最大限值集合") diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wq/mapper/WqJobMapper.java b/backend/src/main/java/com/yfd/platform/qgc_env/wq/mapper/WqJobMapper.java new file mode 100644 index 00000000..b1e778bd --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wq/mapper/WqJobMapper.java @@ -0,0 +1,18 @@ +package com.yfd.platform.qgc_env.wq.mapper; + +import com.yfd.platform.qgc_env.wq.entity.SdWqR; +import com.yfd.platform.qgc_env.wq.entity.ao.JobBaseAo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface WqJobMapper { + + List getWqLastData(@Param("ao") JobBaseAo ao); + + List getWqYsLastData(@Param("startTimeStr") String startTimeStr, @Param("endTimeStr") String endTimeStr); + + void mergeWqR(@Param("wqRs") List wqRs); +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/EnvWqDataService.java b/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/EnvWqDataService.java index f2ff1e22..0ba9565b 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/EnvWqDataService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/EnvWqDataService.java @@ -3,6 +3,7 @@ package com.yfd.platform.qgc_env.wq.service; import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceResult; import com.yfd.platform.qgc_base.entity.vo.BatchDeleteAo; +import com.yfd.platform.qgc_env.wq.entity.ao.JobBaseAo; import com.yfd.platform.qgc_env.wq.entity.vo.WqBaseInfoVo; import com.yfd.platform.qgc_env.wq.entity.vo.EnvWqAnchorPointVo; @@ -45,4 +46,6 @@ public interface EnvWqDataService { boolean removeKendoByIds(BatchDeleteAo batchDeleteAo); DataSourceResult getAnchorPointKendoListCust(DataSourceRequest dataSourceRequest); + + void wqLastData(JobBaseAo ao); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/impl/EnvWqDataServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/impl/EnvWqDataServiceImpl.java index 4e9657f9..e45490d4 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/impl/EnvWqDataServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/impl/EnvWqDataServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.common.*; import com.yfd.platform.common.exception.BizException; @@ -15,15 +16,16 @@ import com.yfd.platform.qgc_base.entity.vo.DataParam; import com.yfd.platform.qgc_base.mapper.MsOperationLogDetailMapper; import com.yfd.platform.qgc_base.mapper.MsOperationLogMapper; import com.yfd.platform.qgc_base.service.IDataScopeFilterService; +import com.yfd.platform.qgc_env.wq.entity.SdWqR; +import com.yfd.platform.qgc_env.wq.entity.ao.JobBaseAo; import com.yfd.platform.qgc_env.wq.entity.vo.*; +import com.yfd.platform.qgc_env.wq.mapper.WqJobMapper; import com.yfd.platform.qgc_env.wq.service.EnvWqDataService; import com.yfd.platform.qgc_env.wt.entity.vo.WbsbVo; import com.yfd.platform.qgc_env.wt.utils.SiteAvoidanceUtils; -import com.yfd.platform.utils.KendoUtil; -import com.yfd.platform.utils.QgcQueryWrapperUtil; -import com.yfd.platform.utils.RequestHolder; -import com.yfd.platform.utils.SecurityUtils; +import com.yfd.platform.utils.*; import jakarta.annotation.Resource; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.jdbc.core.JdbcTemplate; @@ -50,6 +52,9 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { @Resource private IDataScopeFilterService dataScopeFilterService; + @Resource + private RedisCacheUtil redisCacheUtil; + private static final String WQ_HOUR_TABLE_NAME = "SD_WQ_R"; private static final String WQ_DAY_TABLE_NAME = "SD_WQDAY_S"; private static final String WQ_MONTH_TABLE_NAME = "SD_WQDRTP_S"; @@ -158,6 +163,9 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { @Resource private MsOperationLogDetailMapper msOperationLogDetailMapper; + @Resource + private WqJobMapper wqJobMapper; + @Override public DataSourceResult processKendoList(DataSourceRequest dataSourceRequest) { boolean calculated = CommonConstant.CALCULATE_SUCCESS.equals( @@ -4549,6 +4557,7 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { } @Override +// @Cacheable(cacheNames = "weCache#3600", keyGenerator = "cacheKeyGenerator") public DataSourceResult getAnchorPointKendoListCust(DataSourceRequest dataSourceRequest) { DataSourceResult dataSourceResult = new DataSourceResult<>(); dataSourceResult.setAggregates(new HashMap<>()); @@ -4575,6 +4584,15 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { .append("t.ELEV AS dtmel, ") .append("t.STLC AS stlc, ") .append("t.WWQTG AS wwqtg, ") + .append("CASE t.WWQTG " + + " WHEN '1' THEN 'Ⅰ' " + + " WHEN '2' THEN 'Ⅱ' " + + " WHEN '3' THEN 'Ⅲ' " + + " WHEN '4' THEN 'Ⅳ' " + + " WHEN '5' THEN 'Ⅴ' " + + " WHEN '6' THEN 'V' " + + " ELSE '未知' " + + "END AS wwqtgName,") .append("t.DTIN_TYPE AS dtinType, ") .append("t.RSTCD AS rstcd, ") .append("t.FHSTCD AS fhstcd, ") @@ -4640,15 +4658,16 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { .distinct() .collect(Collectors.toList()); - List wqDataList = queryWqDataByStcdBatch(stcdList); - Map wqDataMap = wqDataList.stream() - .collect(Collectors.toMap(EnvWqDataVo::getStcd, Function.identity(), (oldValue, newValue) -> newValue)); +// List wqDataList = queryWqDataByStcdBatch(stcdList); +// Map wqDataMap = wqDataList.stream() +// .collect(Collectors.toMap(EnvWqDataVo::getStcd, Function.identity(), (oldValue, newValue) -> newValue)); for (EnvWqAnchorPointVo anchorPointVo : wqVoList) { - EnvWqDataVo wqData = wqDataMap.get(anchorPointVo.getStcd()); + EnvWqDataVo wqData = redisCacheUtil.fromJson(redisCacheUtil.getString("wqLastDate:" + anchorPointVo.getStcd()), EnvWqDataVo.class); if (wqData != null) { anchorPointVo.setTm(wqData.getTm()); anchorPointVo.setWqGrd(wqData.getWqgrd()); + anchorPointVo.setWqGrdName(wqData.getWqgrdName()); anchorPointVo.setSfdb(wqData.getSfdb()); anchorPointVo.setWtmp(wqData.getWtmp()); anchorPointVo.setPh(wqData.getPh()); @@ -4730,7 +4749,7 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { .map(s -> "'" + s + "'") .collect(Collectors.joining(",")); - String wqDataSql = "SELECT STCD, TM, WQGRD, SFDB, WTMP, PH, DOX, CODMN, CODCR, BOD5, NH3N, TP, TN, CU, ZN, F, SE, ARS, HG, CD, CR6, PB, CN, VLPH, OIL, LAS, S2, FCG, CL, SO4, NO3, THRD, COND, FE, MN, AL, CHLA, CLARITY, TU, CYANO, TOD " + + String wqDataSql = "SELECT STCD, TM, WQGRD,CASE WQGRD WHEN '1' THEN 'Ⅰ' WHEN '2' THEN 'Ⅱ' WHEN '3' THEN 'Ⅲ' WHEN '4' THEN 'Ⅳ' WHEN '5' THEN 'Ⅴ' WHEN '6' THEN 'V' ELSE '未知' END AS wqgrdName, SFDB, WTMP, PH, DOX, CODMN, CODCR, BOD5, NH3N, TP, TN, CU, ZN, F, SE, ARS, HG, CD, CR6, PB, CN, VLPH, OIL, LAS, S2, FCG, CL, SO4, NO3, THRD, COND, FE, MN, AL, CHLA, CLARITY, TU, CYANO, TOD " + "FROM ( " + " SELECT t.*, ROW_NUMBER() OVER (PARTITION BY t.STCD ORDER BY t.TM DESC) AS rn " + " FROM SD_WQ_R t " + @@ -4952,4 +4971,29 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { } } } + + @Override + public void wqLastData(JobBaseAo ao) { + List wqDataVos = wqJobMapper.getWqLastData(ao); + String startTimeStr = DateUtil.format(ao.getStartTime(), "yyyy-MM-dd HH:mm:ss"); + String endTimeStr = DateUtil.format(ao.getEndTime(), "yyyy-MM-dd HH:mm:ss"); + List wqYsDataVos = wqJobMapper.getWqYsLastData(startTimeStr, endTimeStr); + if (CollectionUtils.isNotEmpty(wqYsDataVos)) { + for (SdWqR wqDataVo : wqYsDataVos) { + redisCacheUtil.setString("wqYsLastDate:" + wqDataVo.getStcd(), JSONUtil.toJsonStr(wqDataVo)); + } + } + if (CollUtil.isEmpty(wqDataVos)) { + return; + } + if (!wqDataVos.isEmpty()) { + List> newWqrListPartition = CollUtil.split(wqDataVos, 300); + for (List t : newWqrListPartition) { + wqJobMapper.mergeWqR(t); + } + } + for (SdWqR wqDataVo : wqDataVos) { + redisCacheUtil.setString("wqLastDate:" + wqDataVo.getStcd(), JSONUtil.toJsonStr(wqDataVo)); + } + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtMonitorServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtMonitorServiceImpl.java index 5aa6b96f..1e3d7581 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtMonitorServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtMonitorServiceImpl.java @@ -27,7 +27,10 @@ import com.yfd.platform.qgc_env.wt.entity.vo.WaterTempMapVO; import com.yfd.platform.qgc_env.wt.mapper.SdWtMonitorMapper; import com.yfd.platform.qgc_env.wt.utils.SiteAvoidanceUtils; import com.yfd.platform.qgc_env.wt.service.SdWtMonitorService; +import com.yfd.platform.qgc_job.vo.WtLastDataVo; +import com.yfd.platform.qgc_job.vo.WtvtPointVo; import com.yfd.platform.utils.QgcQueryWrapperUtil; +import com.yfd.platform.utils.RedisCacheUtil; import com.yfd.platform.utils.SecurityUtils; import jakarta.annotation.Resource; import lombok.Data; @@ -63,6 +66,9 @@ public class SdWtMonitorServiceImpl implements SdWtMonitorService { @Resource private IDataScopeFilterService dataScopeFilterService; + @Resource + private RedisCacheUtil redisCacheUtil; + @Override public DataSourceResult getEvnmAutoMonitorList(DataSourceRequest dataSourceRequest) { DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); @@ -3044,6 +3050,19 @@ public class SdWtMonitorServiceImpl implements SdWtMonitorService { vo.setAnchoPointState("WT_2"); } } + + if(vo.getEnfc()==1){ + //垂向水温 + WtvtPointVo wtvtPointVo =redisCacheUtil.fromJson(redisCacheUtil.getString("wtvtPointData:" + vo.getStcd()), WtvtPointVo.class); + vo.setWtvtInfo(wtvtPointVo); + }else{ + //河道水温 + WtLastDataVo sdWtrvR = redisCacheUtil.fromJson(redisCacheUtil.getString("wtLastData:" + vo.getStcd()), WtLastDataVo.class); + if(sdWtrvR !=null){ + vo.setTm(sdWtrvR.getTm()); + vo.setTemperature(sdWtrvR.getWt()); + } + } } SiteAvoidanceUtils.calcSiteMapLev(resultList, diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/impl/WeFishServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/impl/WeFishServiceImpl.java index cfefb4b9..45316df3 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/impl/WeFishServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/impl/WeFishServiceImpl.java @@ -16,6 +16,7 @@ import com.yfd.platform.qgc_env.wte.service.WeFishService; import com.yfd.platform.utils.KendoUtil; import com.yfd.platform.utils.QgcQueryWrapperUtil; import jakarta.annotation.Resource; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.math.BigDecimal; @@ -1035,6 +1036,7 @@ public class WeFishServiceImpl implements WeFishService { } @Override + @Cacheable(cacheNames = "weCache#3600", keyGenerator = "cacheKeyGenerator") public DataSourceResult getQgcWeFishPoint(DataSourceRequest dataSourceRequest) { DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); String stcd = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "stcd"); @@ -1067,6 +1069,7 @@ public class WeFishServiceImpl implements WeFishService { } @Override + @Cacheable(cacheNames = "weCache#3600", keyGenerator = "cacheKeyGenerator") public DataSourceResult getQgcWePoint(DataSourceRequest dataSourceRequest) { DataSourceResult result = new DataSourceResult<>(); result.setAggregates(new HashMap<>()); diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/impl/ZqMonitorServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/impl/ZqMonitorServiceImpl.java index 75b64aed..85743199 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/impl/ZqMonitorServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/impl/ZqMonitorServiceImpl.java @@ -24,7 +24,9 @@ import com.yfd.platform.qgc_env.zq.entity.vo.ZqRiverDrtpDataVo; import com.yfd.platform.qgc_env.zq.entity.vo.ZqRiverDataVo; import com.yfd.platform.qgc_env.wt.utils.SiteAvoidanceUtils; import com.yfd.platform.qgc_env.zq.service.ZqMonitorService; +import com.yfd.platform.qgc_job.vo.ZqLastDataVo; import com.yfd.platform.utils.QgcQueryWrapperUtil; +import com.yfd.platform.utils.RedisCacheUtil; import com.yfd.platform.utils.SecurityUtils; import jakarta.annotation.Resource; import org.springframework.cache.annotation.Cacheable; @@ -50,7 +52,6 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { private static final String ZQ_MONTH_TABLE_NAME = "SD_RIVERDRTP_S"; private static final Map ZQ_UPDATE_COLUMN_MAP = new LinkedHashMap<>(); private static final Map ZQ_FIELD_MEANING_MAP = new LinkedHashMap<>(); - static { ZQ_UPDATE_COLUMN_MAP.put("z", "Z"); ZQ_UPDATE_COLUMN_MAP.put("q", "Q"); @@ -90,6 +91,8 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { @Resource private MsOperationLogDetailMapper msOperationLogDetailMapper; + @Resource + private RedisCacheUtil redisCacheUtil; @Override @Cacheable(cacheNames = "zqCache#7200", keyGenerator = "cacheKeyGenerator") @@ -2374,6 +2377,7 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { } @Override + @Cacheable(cacheNames = "zqCache#3600", keyGenerator = "cacheKeyGenerator") public DataSourceResult getZqPointKendoListCust(DataSourceRequest dataSourceRequest) { DataSourceResult dataSourceResult = new DataSourceResult<>(); dataSourceResult.setAggregates(new HashMap<>()); @@ -2440,7 +2444,16 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { Page page = QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); List resultList = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, ZqPoint.class); - + resultList.forEach(item->{ + //获取流量站最新数据 + ZqLastDataVo zqLastData = redisCacheUtil.fromJson(redisCacheUtil.getString("zqLastData:"+item.getStcd()), ZqLastDataVo.class); + if(zqLastData !=null){ + item.setTm(zqLastData.getTm()); + item.setQ(zqLastData.getQ()); + item.setZ(zqLastData.getZ()); + item.setV(zqLastData.getV()); + } + }); SiteAvoidanceUtils.calcSiteMapLev(resultList, ZqPoint::getStcd, ZqPoint::getLgtd, diff --git a/backend/src/main/java/com/yfd/platform/qgc_job/service/IDwJobService.java b/backend/src/main/java/com/yfd/platform/qgc_job/service/IDwJobService.java new file mode 100644 index 00000000..dff8a481 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_job/service/IDwJobService.java @@ -0,0 +1,10 @@ +package com.yfd.platform.qgc_job.service; + +import com.yfd.platform.qgc_env.wq.entity.ao.JobBaseAo; + +public interface IDwJobService { + + void wtLastData(JobBaseAo ao); + + void wtvtPointData(JobBaseAo ao); +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_job/service/IEqJobService.java b/backend/src/main/java/com/yfd/platform/qgc_job/service/IEqJobService.java new file mode 100644 index 00000000..05285586 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_job/service/IEqJobService.java @@ -0,0 +1,8 @@ +package com.yfd.platform.qgc_job.service; + +import com.yfd.platform.qgc_env.wq.entity.ao.JobBaseAo; + +public interface IEqJobService { + + void eqAnchorPointLastDate(JobBaseAo ao); +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_job/service/IFhJobService.java b/backend/src/main/java/com/yfd/platform/qgc_job/service/IFhJobService.java new file mode 100644 index 00000000..5b7b8f0b --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_job/service/IFhJobService.java @@ -0,0 +1,8 @@ +package com.yfd.platform.qgc_job.service; + +import com.yfd.platform.qgc_env.wq.entity.ao.JobBaseAo; + +public interface IFhJobService { + + void zqLastData(JobBaseAo ao); +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_job/service/impl/DwJobServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_job/service/impl/DwJobServiceImpl.java new file mode 100644 index 00000000..894253ff --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_job/service/impl/DwJobServiceImpl.java @@ -0,0 +1,291 @@ +package com.yfd.platform.qgc_job.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.json.JSONUtil; +import com.yfd.platform.common.MicroservicDynamicSQLMapper; +import com.yfd.platform.qgc_env.wq.entity.ao.JobBaseAo; +import com.yfd.platform.qgc_job.service.IDwJobService; +import com.yfd.platform.qgc_job.vo.WtLastDataVo; +import com.yfd.platform.qgc_job.vo.WtvtPointDataVo; +import com.yfd.platform.qgc_job.vo.WtvtPointVo; +import com.yfd.platform.utils.RedisCacheUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Slf4j +@Service +public class DwJobServiceImpl implements IDwJobService { + + private static final String WT_LAST_DATA_KEY_PREFIX = "wtLastData:"; + private static final String WTVT_POINT_DATA_KEY_PREFIX = "wtvtPointData:"; + + @Resource + private MicroservicDynamicSQLMapper microservicDynamicSQLMapper; + + @Resource + private RedisCacheUtil redisCacheUtil; + + @Override + public void wtLastData(JobBaseAo ao) { + if (ao == null) { + throw new RuntimeException("任务参数不能为空"); + } + ao.initTime(); + Date startTime = ao.getStartTime(); + Date endTime = ao.getEndTime(); + Set stcds = ao.getStcds(); + + List> dateList = getInterValDate(startTime, endTime); + Map lastDataMap = new LinkedHashMap<>(); + for (int index = dateList.size() - 1; index >= 0; index--) { + Map dateMap = dateList.get(index); + Date segmentStartTime = dateMap.get("startTime"); + Date segmentEndTime = dateMap.get("endTime"); + List wtLastDataList = getWtLastData(stcds, segmentStartTime, segmentEndTime); + for (WtLastDataVo wtLastDataVo : wtLastDataList) { + if (wtLastDataVo == null || wtLastDataVo.getStcd() == null || lastDataMap.containsKey(wtLastDataVo.getStcd())) { + continue; + } + lastDataMap.put(wtLastDataVo.getStcd(), wtLastDataVo); + } + } + + int count = 0; + for (Map.Entry entry : lastDataMap.entrySet()) { + String stcd = entry.getKey(); + WtLastDataVo wtLastDataVo = entry.getValue(); + WtLastDataVo redisData = redisCacheUtil.fromJson(redisCacheUtil.getString(WT_LAST_DATA_KEY_PREFIX + stcd), WtLastDataVo.class); + if (shouldRefresh(redisData, wtLastDataVo)) { + redisCacheUtil.setString(WT_LAST_DATA_KEY_PREFIX + stcd, JSONUtil.toJsonStr(wtLastDataVo)); + count++; + } else { + redisCacheUtil.delete(WT_LAST_DATA_KEY_PREFIX + stcd); + } + } + log.info("本次更新水温缓存{}条", count); + } + + @Override + public void wtvtPointData(JobBaseAo ao) { + if (ao == null) { + throw new RuntimeException("任务参数不能为空"); + } + ao.initTime(); + Date startTime = ao.getStartTime(); + Date endTime = ao.getEndTime(); + Set stcds = ao.getStcds(); + + List> dateList = getInterValDate(startTime, endTime); + Map> lastDataMap = new LinkedHashMap<>(); + for (int index = dateList.size() - 1; index >= 0; index--) { + Map dateMap = dateList.get(index); + Date segmentStartTime = dateMap.get("startTime"); + Date segmentEndTime = dateMap.get("endTime"); + List wtvtLastDataList = getWtvtPointLastData(stcds, segmentStartTime, segmentEndTime); + if (CollUtil.isEmpty(wtvtLastDataList)) { + continue; + } + Map> groupedMap = new LinkedHashMap<>(); + for (WtvtPointDataVo wtvtPointDataVo : wtvtLastDataList) { + if (wtvtPointDataVo == null || wtvtPointDataVo.getStcd() == null) { + continue; + } + groupedMap.computeIfAbsent(wtvtPointDataVo.getStcd(), key -> new ArrayList<>()).add(wtvtPointDataVo); + } + for (Map.Entry> entry : groupedMap.entrySet()) { + if (!lastDataMap.containsKey(entry.getKey())) { + lastDataMap.put(entry.getKey(), entry.getValue()); + } + } + } + + int count = 0; + for (Map.Entry> entry : lastDataMap.entrySet()) { + String stcd = entry.getKey(); + WtvtPointVo wtvtPointVo = buildWtvtPointVo(stcd, entry.getValue()); + WtvtPointVo redisData = redisCacheUtil.fromJson(redisCacheUtil.getString(WTVT_POINT_DATA_KEY_PREFIX + stcd), WtvtPointVo.class); + if (shouldRefresh(redisData, wtvtPointVo)) { + redisCacheUtil.setString(WTVT_POINT_DATA_KEY_PREFIX + wtvtPointVo.getStcd(), JSONUtil.toJsonStr(wtvtPointVo)); + count++; + } + } + log.info("本次更新垂向水温缓存{}条", count); + } + + private boolean shouldRefresh(WtLastDataVo redisData, WtLastDataVo currentData) { + if (currentData == null || currentData.getTm() == null) { + return false; + } + return redisData == null || redisData.getTm() == null || DateUtil.compare(redisData.getTm(), currentData.getTm()) < 0; + } + + private boolean shouldRefresh(WtvtPointVo redisData, WtvtPointVo currentData) { + if (currentData == null || currentData.getTm() == null) { + return false; + } + return redisData == null || redisData.getTm() == null || DateUtil.compare(redisData.getTm(), currentData.getTm()) < 0; + } + + private List getWtLastData(Set stcds, Date startTime, Date endTime) { + Map paramMap = new HashMap<>(); + paramMap.put("startTime", startTime); + paramMap.put("endTime", endTime); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append(" data.ID AS id, ") + .append(" data.STCD AS stcd, ") + .append(" data.TM AS tm, ") + .append(" data.WT AS wt, ") + .append(" data.REMARK AS remark, ") + .append(" data.FID AS fid, ") + .append(" data.RECORD_USER AS recordUser, ") + .append(" data.RECORD_TIME AS recordTime, ") + .append(" data.MODIFY_USER AS modifyUser, ") + .append(" data.MODIFY_TIME AS modifyTime, ") + .append(" data.IS_DELETED AS isDeleted, ") + .append(" data.DELETE_USER AS deleteUser, ") + .append(" data.DELETE_TIME AS deleteTime ") + .append("FROM ( ") + .append(" SELECT t.*, ROW_NUMBER() OVER (PARTITION BY t.STCD ORDER BY t.TM DESC, t.RECORD_TIME DESC, t.ID DESC) AS rn ") + .append(" FROM SD_WTRV_R t ") + .append(" WHERE NVL(t.IS_DELETED, 0) = 0 ") + .append(" AND t.TM >= #{map.startTime} ") + .append(" AND t.TM <= #{map.endTime} "); + appendInCondition(sql, paramMap, "t.STCD", stcds, "wtLastDataStcd"); + sql.append(") data WHERE data.rn = 1"); + return microservicDynamicSQLMapper.getAllListWithResultType(sql.toString(), paramMap, WtLastDataVo.class); + } + + private List getWtvtPointLastData(Set stcds, Date startTime, Date endTime) { + Map paramMap = new HashMap<>(); + paramMap.put("startTime", startTime); + paramMap.put("endTime", endTime); + + StringBuilder sql = new StringBuilder(); + sql.append("WITH temp AS ( ") + .append(" SELECT STCD, VWT, TM, WTHG ") + .append(" FROM ( ") + .append(" SELECT STCD, VWT, TM, WTHG, DENSE_RANK() OVER (PARTITION BY STCD ORDER BY TM DESC) AS rn ") + .append(" FROM SD_WTVT_R ") + .append(" WHERE NVL(IS_DELETED, 0) = 0 ") + .append(" AND TM >= #{map.startTime} ") + .append(" AND TM <= #{map.endTime} "); + appendInCondition(sql, paramMap, "STCD", stcds, "wtvtPointDataStcd"); + sql.append(" ) ") + .append(" WHERE rn = 1 ") + .append(") ") + .append("SELECT ") + .append(" t1.STCD AS stcd, ") + .append(" t2.TM AS tm, ") + .append(" t1.AVGWT AS avgwt, ") + .append(" t2.VWT AS vwt, ") + .append(" t2.WTHG AS wthg, ") + .append(" t2.MINRN AS minrn, ") + .append(" t2.MAXRN AS maxrn ") + .append("FROM ( ") + .append(" SELECT STCD, ROUND(AVG(VWT), 2) AS AVGWT ") + .append(" FROM temp GROUP BY STCD ") + .append(") t1 ") + .append("INNER JOIN ( ") + .append(" SELECT * FROM ( ") + .append(" SELECT ") + .append(" STCD, VWT, TM, WTHG, ") + .append(" ROW_NUMBER() OVER (PARTITION BY STCD ORDER BY WTHG ASC) AS minrn, ") + .append(" ROW_NUMBER() OVER (PARTITION BY STCD ORDER BY WTHG DESC) AS maxrn ") + .append(" FROM temp ") + .append(" ) WHERE MINRN = 1 OR MAXRN = 1 ") + .append(") t2 ON t1.STCD = t2.STCD"); + return microservicDynamicSQLMapper.getAllListWithResultType(sql.toString(), paramMap, WtvtPointDataVo.class); + } + + private WtvtPointVo buildWtvtPointVo(String stcd, List wtvtPointDataVoList) { + WtvtPointVo wtvtPointVo = new WtvtPointVo(); + wtvtPointVo.setStcd(stcd); + if (CollUtil.isEmpty(wtvtPointDataVoList)) { + return wtvtPointVo; + } + for (WtvtPointDataVo wtvtPointDataVo : wtvtPointDataVoList) { + if (wtvtPointDataVo == null) { + continue; + } + wtvtPointVo.setTm(wtvtPointDataVo.getTm()); + wtvtPointVo.setAvgWt(wtvtPointDataVo.getAvgwt()); + if (Integer.valueOf(1).equals(wtvtPointDataVo.getMinrn())) { + wtvtPointVo.setMinWthg(wtvtPointDataVo.getWthg()); + wtvtPointVo.setMinWthgWt(wtvtPointDataVo.getVwt()); + } + if (Integer.valueOf(1).equals(wtvtPointDataVo.getMaxrn())) { + wtvtPointVo.setMaxWthg(wtvtPointDataVo.getWthg()); + wtvtPointVo.setMaxWthgWt(wtvtPointDataVo.getVwt()); + } + } + return wtvtPointVo; + } + + // 以指定时间间隔分隔开始时间和结束时间,保持旧平台 7 天分段口径 + private List> getInterValDate(Date startTime, Date endTime) { + int num = 7; + List> dateList = new ArrayList<>(); + long interval = DateUtil.betweenDay(startTime, endTime, false); + if (interval <= num) { + Map dateMap = new HashMap<>(); + dateMap.put("startTime", startTime); + dateMap.put("endTime", endTime); + dateList.add(dateMap); + return dateList; + } + while (startTime.getTime() < endTime.getTime()) { + Map dateMap = new HashMap<>(); + DateTime dateTime = DateUtil.offsetDay(startTime, num); + dateMap.put("startTime", startTime); + if (dateTime.getTime() < endTime.getTime()) { + dateMap.put("endTime", DateUtil.offsetSecond(dateTime, -1)); + } else { + dateMap.put("endTime", endTime); + } + dateList.add(dateMap); + startTime = dateTime; + } + dateList.sort(Comparator.comparing(item -> item.get("startTime"))); + return dateList; + } + + private void appendInCondition(StringBuilder sql, + Map paramMap, + String column, + Set values, + String prefix) { + if (CollUtil.isEmpty(values)) { + return; + } + List placeholders = new ArrayList<>(); + int index = 0; + for (String value : values) { + if (value == null || value.trim().isEmpty()) { + continue; + } + String key = prefix + index++; + paramMap.put(key, value.trim()); + placeholders.add("#{map." + key + "}"); + } + if (CollUtil.isEmpty(placeholders)) { + return; + } + sql.append(" AND ").append(column).append(" IN (") + .append(String.join(", ", placeholders)) + .append(") "); + } +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_job/service/impl/EqJobServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_job/service/impl/EqJobServiceImpl.java new file mode 100644 index 00000000..d5dcd9ea --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_job/service/impl/EqJobServiceImpl.java @@ -0,0 +1,85 @@ +package com.yfd.platform.qgc_job.service.impl; + +import cn.hutool.json.JSONUtil; +import com.yfd.platform.common.MicroservicDynamicSQLMapper; +import com.yfd.platform.qgc_env.wq.entity.ao.JobBaseAo; +import com.yfd.platform.qgc_job.service.IEqJobService; +import com.yfd.platform.qgc_job.vo.EqAnchorPointLastDateVo; +import com.yfd.platform.utils.RedisCacheUtil; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class EqJobServiceImpl implements IEqJobService { + + @Resource + private MicroservicDynamicSQLMapper microservicDynamicSQLMapper; + + @Resource + private RedisCacheUtil redisCacheUtil; + + @Override + public void eqAnchorPointLastDate(JobBaseAo ao) { + Map paramMap = new HashMap<>(); + // 旧逻辑只按当前时间截取最新一条工程运行数据,ao 在此方法中不参与过滤 + paramMap.put("currentTime", new Date()); + + List eqDataVos = microservicDynamicSQLMapper.getAllListWithResultType( + buildEqAnchorPointLastDateSql(), + paramMap, + EqAnchorPointLastDateVo.class + ); + for (EqAnchorPointLastDateVo eqDataVo : eqDataVos) { + redisCacheUtil.setString("eqAnchorPointLastDate:" + eqDataVo.getStcd(), JSONUtil.toJsonStr(eqDataVo)); + } + } + + private String buildEqAnchorPointLastDateSql() { + return "SELECT " + + "run.STCD AS stcd, " + + "run.TM AS tm, " + + "run.QI AS qi, " + + "run.QO AS qo, " + + "run.RZ AS rz, " + + "run.DZ AS dz, " + + "qec.QEC_LIMIT AS qecLimit, " + + "qec.QEC_C AS qecC, " + + "qec.MWR_LIMIT AS mwrLimit, " + + "qec.MWR_C AS mwrC, " + + "NVL(qec.AVQ_LIMIT, eng.AVQ) AS avqLimit, " + + "qec.AVQ_C AS avqC, " + + "qecDetail.VLSR AS vlsr, " + + "qecDetail.VLSR_TM AS vlsrTm, " + + "mwrDetail.VLSR AS mwrVlsr, " + + "mwrDetail.VLSR_TM AS mwrVlsrTm " + + "FROM ( " + + " SELECT STCD, MAX(TM) AS TM " + + " FROM SD_HYDROPW_R " + + " WHERE NVL(IS_DELETED, 0) = 0 " + + " AND TM <= #{map.currentTime} " + + " GROUP BY STCD " + + ") lastRun " + + "INNER JOIN SD_HYDROPW_R run " + + " ON lastRun.STCD = run.STCD " + + " AND lastRun.TM = run.TM " + + " AND NVL(run.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_QEC_R qec " + + " ON qec.STCD = run.STCD " + + " AND qec.TM = run.TM " + + " AND NVL(qec.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_ENGINFO_B_H eng " + + " ON eng.STCD = run.STCD " + + " AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN MS_WARN_RULE_DETAIL_B qecDetail " + + " ON qecDetail.ID = qec.QEC_RULE_DID " + + " AND NVL(qecDetail.IS_DELETED, 0) = 0 " + + "LEFT JOIN MS_WARN_RULE_DETAIL_B mwrDetail " + + " ON mwrDetail.ID = qec.QEC_MWRRULE_DID " + + " AND NVL(mwrDetail.IS_DELETED, 0) = 0"; + } +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_job/service/impl/FhJobServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_job/service/impl/FhJobServiceImpl.java new file mode 100644 index 00000000..149202f0 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_job/service/impl/FhJobServiceImpl.java @@ -0,0 +1,95 @@ +package com.yfd.platform.qgc_job.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; +import com.yfd.platform.common.MicroservicDynamicSQLMapper; +import com.yfd.platform.qgc_env.wq.entity.ao.JobBaseAo; +import com.yfd.platform.qgc_job.service.IFhJobService; +import com.yfd.platform.qgc_job.vo.ZqLastDataVo; +import com.yfd.platform.utils.RedisCacheUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Slf4j +@Service +public class FhJobServiceImpl implements IFhJobService { + + private static final String ZQ_LAST_DATA_KEY_PREFIX = "zqLastData:"; + + @Resource + private MicroservicDynamicSQLMapper microservicDynamicSQLMapper; + + @Resource + private RedisCacheUtil redisCacheUtil; + + @Override + public void zqLastData(JobBaseAo ao) { + Set stcds = ao == null ? null : ao.getStcds(); + List zqDataVos = getZqLastData(stcds); + if (CollUtil.isEmpty(zqDataVos)) { + return; + } + for (ZqLastDataVo zqDataVo : zqDataVos) { + if (zqDataVo == null || zqDataVo.getStcd() == null) { + continue; + } + redisCacheUtil.setString(ZQ_LAST_DATA_KEY_PREFIX + zqDataVo.getStcd(), JSONUtil.toJsonStr(zqDataVo)); + } + log.info("本次更新河道水情缓存{}条", zqDataVos.size()); + } + + private List getZqLastData(Set stcds) { + Map paramMap = new HashMap<>(); + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append("t.STCD AS stcd, ") + .append("t.Z AS z, ") + .append("t.Q AS q, ") + .append("t.V AS v, ") + .append("t.TM AS tm ") + .append("FROM SD_RIVER_R t ") + .append("INNER JOIN ( ") + .append(" SELECT STCD, MAX(TM) AS tm ") + .append(" FROM SD_RIVER_R ") + .append(" WHERE NVL(IS_DELETED, 0) = 0 "); + appendInCondition(sql, paramMap, "STCD", stcds, "zqLastDataInnerStcd"); + sql.append(" GROUP BY STCD ") + .append(") t1 ON t.STCD = t1.STCD AND t.TM = t1.tm ") + .append("WHERE NVL(t.IS_DELETED, 0) = 0 "); + appendInCondition(sql, paramMap, "t.STCD", stcds, "zqLastDataOuterStcd"); + return microservicDynamicSQLMapper.getAllListWithResultType(sql.toString(), paramMap, ZqLastDataVo.class); + } + + private void appendInCondition(StringBuilder sql, + Map paramMap, + String column, + Set values, + String prefix) { + if (CollUtil.isEmpty(values)) { + return; + } + List placeholders = new ArrayList<>(); + int index = 0; + for (String value : values) { + if (value == null || value.trim().isEmpty()) { + continue; + } + String key = prefix + index++; + paramMap.put(key, value.trim()); + placeholders.add("#{map." + key + "}"); + } + if (CollUtil.isEmpty(placeholders)) { + return; + } + sql.append(" AND ").append(column).append(" IN (") + .append(String.join(", ", placeholders)) + .append(") "); + } +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_job/vo/EqAnchorPointLastDateVo.java b/backend/src/main/java/com/yfd/platform/qgc_job/vo/EqAnchorPointLastDateVo.java new file mode 100644 index 00000000..78889407 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_job/vo/EqAnchorPointLastDateVo.java @@ -0,0 +1,79 @@ +package com.yfd.platform.qgc_job.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +@Data +@Schema(description = "电站锚点最新缓存数据") +public class EqAnchorPointLastDateVo implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "电站编码") + private String stcd; + + @Schema(description = "电站名称") + private String stnm; + + @Schema(description = "数据时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date tm; + + @Schema(description = "装机容量") + private BigDecimal ttpwr; + + @Schema(description = "生态流量限值(环保部)") + private BigDecimal qecLimit; + + @Schema(description = "生态流量限值(水利部)") + private BigDecimal mwrLimit; + + @Schema(description = "生态流量限值(多年平均)") + private BigDecimal avqLimit; + + @Schema(description = "生态流量系数(环保部)") + private BigDecimal qecC; + + @Schema(description = "生态流量系数(水利部)") + private BigDecimal mwrC; + + @Schema(description = "生态流量系数(多年平均)") + private BigDecimal avqC; + + @Schema(description = "正常蓄水位") + private BigDecimal normz; + + @Schema(description = "死水位") + private BigDecimal ddz; + + @Schema(description = "入库流量") + private BigDecimal qi; + + @Schema(description = "出库流量") + private BigDecimal qo; + + @Schema(description = "坝上水位") + private BigDecimal rz; + + @Schema(description = "坝下水位") + private BigDecimal dz; + + @Schema(description = "规则来源") + private String vlsr; + + @Schema(description = "规则来源时间") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date vlsrTm; + + @Schema(description = "规则来源(水利部)") + private String mwrVlsr; + + @Schema(description = "规则来源时间(水利部)") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date mwrVlsrTm; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_job/vo/WtLastDataVo.java b/backend/src/main/java/com/yfd/platform/qgc_job/vo/WtLastDataVo.java new file mode 100644 index 00000000..0b2046b2 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_job/vo/WtLastDataVo.java @@ -0,0 +1,59 @@ +package com.yfd.platform.qgc_job.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +@Data +@Schema(description = "水温最新缓存数据") +public class WtLastDataVo implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + private String id; + + @Schema(description = "站点编码") + private String stcd; + + @Schema(description = "数据时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date tm; + + @Schema(description = "水温") + private BigDecimal wt; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "附件ID") + private String fid; + + @Schema(description = "创建人") + private String recordUser; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date recordTime; + + @Schema(description = "更新人") + private String modifyUser; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date modifyTime; + + @Schema(description = "是否删除") + private Integer isDeleted; + + @Schema(description = "删除人") + private String deleteUser; + + @Schema(description = "删除时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date deleteTime; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_job/vo/WtvtPointDataVo.java b/backend/src/main/java/com/yfd/platform/qgc_job/vo/WtvtPointDataVo.java new file mode 100644 index 00000000..7af5d3ed --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_job/vo/WtvtPointDataVo.java @@ -0,0 +1,37 @@ +package com.yfd.platform.qgc_job.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +@Schema(description = "垂向水温锚点中间数据") +public class WtvtPointDataVo implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "站点编码") + private String stcd; + + @Schema(description = "数据时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date tm; + + @Schema(description = "平均水温") + private Double avgwt; + + @Schema(description = "水温") + private Double vwt; + + @Schema(description = "测量深度") + private Double wthg; + + @Schema(description = "最小深度行号") + private Integer minrn; + + @Schema(description = "最大深度行号") + private Integer maxrn; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_job/vo/WtvtPointVo.java b/backend/src/main/java/com/yfd/platform/qgc_job/vo/WtvtPointVo.java new file mode 100644 index 00000000..1ec24ba9 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_job/vo/WtvtPointVo.java @@ -0,0 +1,37 @@ +package com.yfd.platform.qgc_job.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +@Schema(description = "垂向水温锚点缓存数据") +public class WtvtPointVo implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "站点编码") + private String stcd; + + @Schema(description = "数据时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date tm; + + @Schema(description = "平均温度") + private Double avgWt; + + @Schema(description = "最大测量深度") + private Double maxWthg; + + @Schema(description = "最大测量深度水温") + private Double maxWthgWt; + + @Schema(description = "最小测量深度") + private Double minWthg; + + @Schema(description = "最小测量深度水温") + private Double minWthgWt; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_job/vo/ZqLastDataVo.java b/backend/src/main/java/com/yfd/platform/qgc_job/vo/ZqLastDataVo.java new file mode 100644 index 00000000..9aff5c5b --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_job/vo/ZqLastDataVo.java @@ -0,0 +1,27 @@ +package com.yfd.platform.qgc_job.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@Schema(description = "河道水情最新缓存") +public class ZqLastDataVo { + + @Schema(description = "站码") + private String stcd; + + @Schema(description = "水位") + private BigDecimal z; + + @Schema(description = "流量") + private BigDecimal q; + + @Schema(description = "流速") + private BigDecimal v; + + @Schema(description = "时间") + private Date tm; +} diff --git a/backend/src/main/java/com/yfd/platform/utils/RedisCacheUtil.java b/backend/src/main/java/com/yfd/platform/utils/RedisCacheUtil.java index 2640763f..0afb6807 100644 --- a/backend/src/main/java/com/yfd/platform/utils/RedisCacheUtil.java +++ b/backend/src/main/java/com/yfd/platform/utils/RedisCacheUtil.java @@ -1,6 +1,9 @@ package com.yfd.platform.utils; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; @@ -12,8 +15,9 @@ import java.util.Set; import java.util.concurrent.TimeUnit; @Component +@Slf4j public class RedisCacheUtil { - + static final ObjectMapper objectMapper = new ObjectMapper(); @Resource private RedisTemplate redisTemplate; @@ -41,6 +45,21 @@ public class RedisCacheUtil { return (T) value; } + public T fromJson(String json, Class clazz) { + if (!StringUtils.isBlank(json) && clazz != null) { + try { + return (T)objectMapper.readValue(json, clazz); + } catch (Exception var4) { + if (log.isErrorEnabled()) { + log.error(var4.getMessage(), var4); + } + return null; + } + } else { + return null; + } + } + public Object get(String key) { return redisTemplate.opsForValue().get(key); } diff --git a/backend/src/main/resources/mapper/qgc_env/wq/WqJobMapper.xml b/backend/src/main/resources/mapper/qgc_env/wq/WqJobMapper.xml new file mode 100644 index 00000000..27da8341 --- /dev/null +++ b/backend/src/main/resources/mapper/qgc_env/wq/WqJobMapper.xml @@ -0,0 +1,56 @@ + + + + + + + + + + MERGE INTO SD_WQ_R T + USING ( + + SELECT #{wqR.id,jdbcType=VARCHAR} AS ID + , #{wqR.wqgrd,jdbcType=VARCHAR} AS WQGRD + , #{wqR.sfdb,jdbcType=NUMERIC} AS SFDB + , #{wqR.wqSfdbhnYs,jdbcType=VARCHAR} AS WQ_SFDBHN_YS + , SYSDATE AS MODIFY_TIME + FROM DUAL + + ) S + ON (T.ID = S.ID) + WHEN MATCHED THEN + UPDATE SET T.WQGRD = S.WQGRD, T.SFDB = S.SFDB, T.WQ_SFDBHN_YS = S.WQ_SFDBHN_YS, T.MODIFY_TIME = S.MODIFY_TIME + + + \ No newline at end of file