diff --git a/docker-compose.yml b/docker-compose.yml index 2918b66..ac7f75c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ services: environment: - TZ=Asia/Shanghai ports: - - 6369:6379 + - 6359:6379 networks: - tsg_tsg-bridge volumes: @@ -19,6 +19,22 @@ services: - /opt/ss/redis/data:/data command: redis-server /usr/local/etc/redis/conf/redis.conf + ss-es: + container_name: ss-es + image: docker.1ms.run/elasticsearch:8.12.2 + environment: + - 'ELASTIC_PASSWORD=1234567a' + - discovery.type=single-node + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + - xpack.security.http.ssl.enabled=false + - xpack.security.enabled=false + - ES_SETTING_XPACK_SECURITY_ENABLED=false + ports: + - "9201:9200" + - "9400:9300" + networks: + - tsg_tsg-bridge + ss-proj: container_name: ss-proj image: openjdk:21 @@ -34,6 +50,7 @@ services: - TZ=Asia/Shanghai depends_on: - ss-redis + - ss-es entrypoint: java -cp "gunshi-project-ss-1.0-SNAPSHOT.jar:./lib/*" com.gunshi.project.ss.Main ss-datasync: diff --git a/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskGnssRMapper.java b/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskGnssRMapper.java index 948a654..9e2f376 100644 --- a/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskGnssRMapper.java +++ b/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskGnssRMapper.java @@ -230,4 +230,12 @@ public interface JcskGnssRMapper extends BaseMapper { """) Page artificialPage(Page page,@Param("dto") JcskGnssRPageSo page1); + + @Select(""" + select t2.* from jcsk_gnss_b t1 + join jcsk_gnss_r t2 on t1.cd = t2.cd + where t1.cd_nm = #{cdnm} + order by t2.tm desc limit 1 +""") + JcskGnssR queryByCDNM(@Param("cdnm") String stationCode); } diff --git a/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskSlRMapper.java b/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskSlRMapper.java index 37b91e8..22b98ec 100644 --- a/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskSlRMapper.java +++ b/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskSlRMapper.java @@ -81,4 +81,12 @@ public interface JcskSlRMapper extends BaseMapper { """) Page historyPage(Page page, JcskSlRPageSo page1); + + @Select(""" + select t2.* from jcsk_sl_b t1 + join jcsk_sl_r t2 on t1.rscd = t2.rscd and t1.mpcd = t2.mpcd + where t1.dvcd = #{dvcd} + order by t2.mstm desc limit 1 +""") + JcskSlR queryByDvcd(@Param("dvcd") String stationCode); } diff --git a/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskSyRMapper.java b/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskSyRMapper.java index dd7d84f..4eb04dd 100644 --- a/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskSyRMapper.java +++ b/module-common/src/main/java/com/gunshi/project/ss/common/mapper/JcskSyRMapper.java @@ -384,4 +384,14 @@ GROUP BY dm ORDER BY tm """) List qeury8AmRz(@Param("dto") OsmoticQuerySo dto, @Param("stcd") String stcd); + + + + @Select(""" + select t2.* from jcsk_sy_b t1 + join jcsk_sy_r t2 on t1.stcd = t2.stcd and t1.mpcd = t2.mpcd + where t1.dvcd = #{dvcd} + order by t2.mstm desc limit 1 +""") + JcskSyR queryByDvcd(@Param("dvcd") String stationCode); } diff --git a/pom.xml b/pom.xml index 50fc8f5..e9c5bde 100644 --- a/pom.xml +++ b/pom.xml @@ -115,6 +115,17 @@ spring-boot-starter-quartz + + + org.springframework.boot + spring-boot-starter-data-elasticsearch + + + org.springframework.data + spring-data-elasticsearch + 5.2.3 + + diff --git a/src/main/java/com/gunshi/project/ss/controller/BusinessRuleController.java b/src/main/java/com/gunshi/project/ss/controller/BusinessRuleController.java new file mode 100644 index 0000000..eae0cab --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/controller/BusinessRuleController.java @@ -0,0 +1,89 @@ +package com.gunshi.project.ss.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gunshi.core.result.R; +import com.gunshi.project.ss.entity.dto.BusinessRuleDto; +import com.gunshi.project.ss.model.BusinessRule; +import com.gunshi.project.ss.model.FileAssociations; +import com.gunshi.project.ss.service.BusinessRuleService; +import com.gunshi.project.ss.service.FileAssociationsService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author lyf + * @since 2025-07-21 + */ +@Tag(name = "业务规则库") +@RestController +@RequestMapping(value = "/businessRule") +public class BusinessRuleController extends AbstractCommonFileController { + @Autowired + private BusinessRuleService service; + + @Autowired + private FileAssociationsService fileService; + + @Operation(summary = "按id查询") + @GetMapping("/getById/{id}") + public BusinessRule getById(@PathVariable("id") Serializable id) { + return service.getOneById(id); + } + + @Operation(summary = "新增") + @PostMapping("/add") + public R add(@RequestBody BusinessRule entity) { + service.add(entity); + if(entity.getFiles() != null){ + fileService.saveFile(entity.getFiles(),getGroupId(),entity.getId().toString()); + } + service.updateEsCache(entity); + return R.ok(entity); + } + + @Operation(summary = "修改") + @PostMapping("/update") + public R update(@RequestBody BusinessRule entity) { + entity.setUpdateTm(new Date()); + boolean flag = service.updateById(entity); + if(!flag){ + throw new IllegalArgumentException("更新失败"); + } + if(entity.getFiles() != null){ + fileService.saveFile(entity.getFiles(),getGroupId(),entity.getId().toString()); + } + service.updateEsCache(entity); + return R.ok(entity); + } + + @Operation(summary = "删除") + @GetMapping("/delete/{id}") + public R delete(@PathVariable("id") Serializable id) { + service.deleteEsCache(id); + boolean flag = service.removeById(id); + fileService.deleteFile(getGroupId(),id.toString()); + return R.ok(flag); + } + + @Operation(summary = "分页") + @PostMapping("/pageByTm") + public R> pageByTm(@RequestBody BusinessRuleDto dto) { + Page page = service.page(dto); + for (BusinessRule record : page.getRecords()) { + List files = fileService.getFiles(getGroupId(), record.getId().toString()); + record.setFiles(files); + } + return R.ok(page); + } + + @Override + public String getGroupId() { + return "businessRule"; + } +} diff --git a/src/main/java/com/gunshi/project/ss/controller/DebugController.java b/src/main/java/com/gunshi/project/ss/controller/DebugController.java index 5676111..36c7174 100644 --- a/src/main/java/com/gunshi/project/ss/controller/DebugController.java +++ b/src/main/java/com/gunshi/project/ss/controller/DebugController.java @@ -1,70 +1,111 @@ package com.gunshi.project.ss.controller; +import com.alibaba.fastjson2.JSONObject; import com.gunshi.core.result.R; +import com.gunshi.project.ss.common.mapper.StStbprpBMapper; +import com.gunshi.project.ss.common.model.JcskGnssB; +import com.gunshi.project.ss.common.model.JcskSlB; +import com.gunshi.project.ss.common.model.JcskSyB; +import com.gunshi.project.ss.common.model.StStbprpB; +import com.gunshi.project.ss.entity.es.EsObjectDocument; +import com.gunshi.project.ss.entity.so.RealRainBaseSo; +import com.gunshi.project.ss.entity.vo.AttResBaseVo; +import com.gunshi.project.ss.entity.vo.AttRvBaseVo; +import com.gunshi.project.ss.entity.vo.RealRainListVo; +import com.gunshi.project.ss.mapper.*; +import com.gunshi.project.ss.model.*; +import com.gunshi.project.ss.repository.TsgObjectRepository; +import com.gunshi.project.ss.service.*; import com.gunshi.project.ss.timetask.JcskDataTask; import com.gunshi.project.ss.timetask.PaDataTask; import com.gunshi.project.ss.timetask.StWaterDataTask; import com.gunshi.project.ss.timetask.WarningRuleTask; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.utils.Lists; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.math.BigDecimal; import java.text.ParseException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; @Tag(name = "后门") @RestController @RequestMapping(value="/debug") +@Slf4j public class DebugController { + @Autowired + private TsgObjectRepository tsgObjectRepository; + + @Autowired + private StStbprpBMapper stStbprpBMapper;//监测站点 + + @Autowired + private AttCctvBaseMapper attCctvBaseMapper;//视频站 + + @Autowired + private IaCDanadMapper iaCDanadMapper;//危险区 + + @Autowired + private ShpPlacementMapper shpPlacementMapper;//安置点 + + @Autowired + private BusinessRuleMapper businessRuleMapper;//业务规则库 + + @Autowired + private DispatchSchemeMapper dispatchSchemeMapper;//调度方案库 + + @Autowired + private ProjectSafetyMapper projectSafetyMapper;//工程安全知识库 + + @Autowired + private IaCBsnssinfoMapper iaCBsnssinfoMapper;//企事业单位 + + @Autowired + private IaCFlrvvlgMapper iaCFlrvvlgMapper;//沿河居民 + + @Autowired + private SoilMoistureStationMapper soilMoistureStationMapper; + + + @Autowired + private BusinessRuleService businessRuleService; + + @Autowired + private DispatchSchemeService dispatchSchemeService; + + @Autowired + private ProjectSafetyService projectSafetyService; + + @Autowired + private ReservoirWaterService reservoirWaterService;//水库水位站(详细数据) + + @Autowired + private RiverWaterService riverWaterService;//河道水位站 + + @Autowired + private RealRainService realRainService;//雨晴(雨量站详细信息) + + @Autowired + private JcskSyBService jcskSyBService; + + @Autowired + private JcskSlBService jcskSlBService; + + @Autowired + private JcskGnssBService jcskGnssBService;// 位移日后可能表需要进行变更 @Autowired private PaDataTask paDataTask; - @Autowired - private JcskDataTask jcskDataTask; - - @Autowired - private WarningRuleTask warningRuleTask; - - @Autowired - private StWaterDataTask stWaterDataTask; - - @GetMapping("/syncWateData") - public String syncWateData() { - try { - stWaterDataTask.syncFlowToWater(); - Thread.sleep(1000); - stWaterDataTask.syncWaterToReorganize(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - return "success"; - } - - @GetMapping("/syRegressionCaculate") - public String syRegressionCaculate(){ - try { - jcskDataTask.calculate(); - return "SUCCESS"; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @GetMapping("/warnRule") - public String warningRuleTast(){ - try { - warningRuleTask.warningRuleExecute(); - return "success"; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @GetMapping("/patask") public String patask(){ try { @@ -75,14 +116,369 @@ public class DebugController { } } - @Operation(description = "同步一次渗压、渗流、位移的数据") - @GetMapping("/syncJcskData") - public R syncJcskData(){ - jcskDataTask.syncGnssREightAmData(); - jcskDataTask.syncSlREightAmData(); + @Operation(description = "获取所有es数据") + @GetMapping("/findAll") + public R findAll(){ + Iterable all = tsgObjectRepository.findAll(); + return R.ok(all); + } - jcskDataTask.syncSyREightAmData(); - return R.ok("ok"); + + @Operation(description = "删除所有es数据") + @GetMapping("/deleteAll") + public R deleteAll(){ + tsgObjectRepository.deleteAll(); + return R.ok(); + } + + @Operation(description = "数据结构的重建") + @GetMapping("/rebuild") + public R rebuild(){ + // 1. 删除现有索引 + ElasticsearchOperations elasticsearchOperations = getElasticsearchOperations(); + if (elasticsearchOperations.indexOps(EsObjectDocument.class).exists()) { + elasticsearchOperations.indexOps(EsObjectDocument.class).delete(); + log.info("索引删除成功"); + } + + // 2. 创建新索引 + elasticsearchOperations.indexOps(EsObjectDocument.class).create(); + log.info("索引创建成功"); + + // 3. 创建映射 + elasticsearchOperations.indexOps(EsObjectDocument.class).putMapping(); + log.info("映射创建成功"); + return R.ok("重建索引成功"); + } + + // 需要注入ElasticsearchOperations + @Autowired + private ElasticsearchOperations elasticsearchOperations; + + private ElasticsearchOperations getElasticsearchOperations() { + return elasticsearchOperations; + } + + + + + + @Operation(description = "填充es数据") + @GetMapping("/cacheEs") + public R cacheEs(){ + tsgObjectRepository.deleteAll(); + List list = Lists.newArrayList(); + //缓存雨量站 + RealRainBaseSo realRainBaseSo = new RealRainBaseSo(); + LocalDateTime now = LocalDateTime.now(); + //设置当前时间 + realRainBaseSo.setStm(now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + //计算一小时之后时间 + LocalDateTime oneHourLater = now.plusHours(1); + realRainBaseSo.setEtm(oneHourLater.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + List realRainList = realRainService.getRealRainList(realRainBaseSo); + for (RealRainListVo entity : realRainList) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getStcd()); + esObjectDocument.setName(entity.getStnm()); + esObjectDocument.setType("雨量站"); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + if(entity.getLgtd() != null){ + esObjectDocument.setLgtd(new BigDecimal(entity.getLgtd())); + } + if(entity.getLttd() != null){ + esObjectDocument.setLttd(new BigDecimal(entity.getLttd())); + } + list.add(esObjectDocument); + } + //缓存至es中 + tsgObjectRepository.saveAll(list); + //清空list + list.clear(); + + //这是水库水位站 + List attResBaseVos = reservoirWaterService.listV2(); + + //List rrList = stStbprpBMapper.getStbprbBySttp("RR"); + for (AttResBaseVo entity : attResBaseVos) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getStcd()); + esObjectDocument.setName(entity.getStnm()); + esObjectDocument.setType("水库水位站"); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + if(entity.getLgtd() != null){ + esObjectDocument.setLgtd(entity.getLgtd()); + } + if(entity.getLgtd() != null){ + esObjectDocument.setLttd(entity.getLttd()); + } + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + + //添加河道水位站 + List rvBaseVoList = riverWaterService.list(); + for (AttRvBaseVo entity : rvBaseVoList) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getStcd()); + esObjectDocument.setName(entity.getStnm()); + esObjectDocument.setType("河道水位站"); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + if(entity.getLgtd() != null){ + esObjectDocument.setLgtd(entity.getLgtd()); + } + if(entity.getLgtd() != null){ + esObjectDocument.setLttd(entity.getLttd()); + } + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + + //视频站 + List cctvList = attCctvBaseMapper.selectList(null); + for (AttCctvBase entity : cctvList) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getIndexCode()); + esObjectDocument.setName(entity.getName()); + esObjectDocument.setType("视频站"); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + if(entity.getLgtd() != null){ + esObjectDocument.setLgtd(new BigDecimal(entity.getLgtd())); + } + if(entity.getLgtd() != null){ + esObjectDocument.setLttd(new BigDecimal(entity.getLttd())); + } + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + + //危险区 + List dandList = iaCDanadMapper.selectList(null); + for (IaCDanad entity : dandList) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getDand()); + esObjectDocument.setName(entity.getName()); + esObjectDocument.setType("危险区"); + esObjectDocument.setLgtd(null); + esObjectDocument.setLttd(null); + esObjectDocument.setGeojson(entity.getGeometry()); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + + + //安置点 + List shpList = shpPlacementMapper.selectList(null); + for (ShpPlacement entity : shpList) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getGid().toString()); + esObjectDocument.setName(entity.getName()); + esObjectDocument.setType("安置点"); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + esObjectDocument.setLgtd(entity.getLgtd() != null ? BigDecimal.valueOf(entity.getLgtd()) : null); + esObjectDocument.setLttd(entity.getLttd() != null ? BigDecimal.valueOf(entity.getLttd()) : null); + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + + //调度方案库 + List dispatchRecordList = dispatchSchemeMapper.selectList(null); + for (DispatchScheme entity : dispatchRecordList) { + DispatchScheme oneById = dispatchSchemeService.getOneById(entity.getId()); + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(String.valueOf(entity.getId())); + esObjectDocument.setName(entity.getName()); + esObjectDocument.setType("调度方案库"); + esObjectDocument.setLgtd(null); + esObjectDocument.setLttd(null); + esObjectDocument.setGeojson(null); + String jsonString = JSONObject.toJSONString(oneById); + esObjectDocument.setJsonStr(jsonString); + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + //业务规则库 + List businessRules = businessRuleMapper.selectList(null); + for (BusinessRule entity : businessRules) { + BusinessRule oneById = businessRuleService.getOneById(entity.getId()); + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(String.valueOf(entity.getId())); + esObjectDocument.setName(entity.getName()); + esObjectDocument.setType("业务规则库"); + esObjectDocument.setLgtd(null); + esObjectDocument.setLttd(null); + esObjectDocument.setGeojson(null); + String jsonString = JSONObject.toJSONString(oneById); + esObjectDocument.setJsonStr(jsonString); + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + // 工程安全知识库 + + List projectSafeties = projectSafetyMapper.selectList(null); + for (ProjectSafety entity : projectSafeties) { + ProjectSafety oneById = projectSafetyService.getOneById(entity.getId()); + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(String.valueOf(entity.getId())); + esObjectDocument.setName(entity.getName()); + esObjectDocument.setType("工程安全知识库"); + esObjectDocument.setLgtd(null); + esObjectDocument.setLttd(null); + esObjectDocument.setGeojson(null); + String jsonString = JSONObject.toJSONString(oneById); + esObjectDocument.setJsonStr(jsonString); + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + + //企事业单位 + List iaCBsnssinfos = iaCBsnssinfoMapper.selectList(null); + for (IaCBsnssinfo entity : iaCBsnssinfos) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getEicd()); + esObjectDocument.setName(entity.getName()); + esObjectDocument.setType("企事业单位"); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + if(entity.getLgtd() != null){ + esObjectDocument.setLgtd(new BigDecimal(entity.getLgtd())); + } + if(entity.getLgtd() != null){ + esObjectDocument.setLttd(new BigDecimal(entity.getLttd())); + } + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + + + List iaCFlrvvlgs = iaCFlrvvlgMapper.selectList(null); + for (IaCFlrvvlg entity : iaCFlrvvlgs) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getAvrcd()); + esObjectDocument.setName(entity.getName()); + esObjectDocument.setType("沿河居民点"); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + if(entity.getLgtd() != null){ + esObjectDocument.setLgtd(new BigDecimal(entity.getLgtd())); + } + if(entity.getLgtd() != null){ + esObjectDocument.setLttd(new BigDecimal(entity.getLttd())); + } + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + + //土壤站 + + List soilMoistureStations = soilMoistureStationMapper.selectList(null); + for (SoilMoistureStation entity : soilMoistureStations) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(String.valueOf(entity.getId())); + esObjectDocument.setName(entity.getStnm()); + esObjectDocument.setType("土壤墒情站"); + esObjectDocument.setLgtd(entity.getLgtd()); + esObjectDocument.setLttd(entity.getLttd()); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + + //流量站 +// List qqList = stStbprpBMapper.select("QQ"); + List qqList = stStbprpBMapper.getFlowStations(); + for (StStbprpB entity : qqList) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getStcd()); + esObjectDocument.setName(entity.getStnm()); + esObjectDocument.setType("流量站"); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + if(entity.getLgtd() != null){ + esObjectDocument.setLgtd(new BigDecimal(entity.getLgtd())); + } + if(entity.getLgtd() != null){ + esObjectDocument.setLttd(new BigDecimal(entity.getLttd())); + } + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + + //渗流 +// List osmoticFlowDevices = osmoticFlowDeviceMapper.selectList(null); + List jcskSlBS = jcskSlBService.getBaseMapper().selectList(null); + for (JcskSlB entity : jcskSlBS) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getDvcd()); + esObjectDocument.setName(entity.getDvcd()); + esObjectDocument.setType("渗流站"); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + if(entity.getLgtd() != null){ + esObjectDocument.setLgtd(entity.getLgtd()); + } + if(entity.getLgtd() != null){ + esObjectDocument.setLttd(entity.getLttd()); + } + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + //渗压 + List jcskSyBS = jcskSyBService.getBaseMapper().selectList(null); + for (JcskSyB entity : jcskSyBS) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getDvcd()); + esObjectDocument.setName(entity.getDvcd()); + esObjectDocument.setType("渗压站"); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + if(entity.getLgtd() != null){ + esObjectDocument.setLgtd(entity.getLgtd()); + } + if(entity.getLgtd() != null){ + esObjectDocument.setLttd(entity.getLttd()); + } + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + //位移站 + List jcskGnssBS = jcskGnssBService.getBaseMapper().selectList(null); + for (JcskGnssB entity : jcskGnssBS) { + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(entity.getCd()); + esObjectDocument.setName(entity.getCd()); + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + esObjectDocument.setType("位移站"); + esObjectDocument.setLgtd(entity.getLgtd()); + esObjectDocument.setLttd(entity.getLttd()); + list.add(esObjectDocument); + } + tsgObjectRepository.saveAll(list); + list.clear(); + return R.ok("数据缓存成功"); } } diff --git a/src/main/java/com/gunshi/project/ss/controller/DispatchSchemeController.java b/src/main/java/com/gunshi/project/ss/controller/DispatchSchemeController.java new file mode 100644 index 0000000..a87a834 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/controller/DispatchSchemeController.java @@ -0,0 +1,97 @@ +package com.gunshi.project.ss.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gunshi.core.result.R; +import com.gunshi.project.ss.entity.dto.DispatchSchemeDto; +import com.gunshi.project.ss.model.DispatchScheme; +import com.gunshi.project.ss.model.FileAssociations; +import com.gunshi.project.ss.service.DispatchSchemeService; +import com.gunshi.project.ss.service.FileAssociationsService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author lyf + * @since 2025-07-21 + */ +@Tag(name = "调度方案库") +@RestController +@RequestMapping(value = "/dispatchScheme") +public class DispatchSchemeController extends AbstractCommonFileController { + @Autowired + private DispatchSchemeService service; + + @Autowired + private FileAssociationsService fileService; + + @Operation(summary = "按id查询") + @GetMapping("/getById/{id}") + public DispatchScheme getById(@PathVariable("id") Serializable id) { + return service.getOneById(id); + } + + @Operation(summary = "获取全部数据") + @GetMapping("getAll") + public List getAll() { + List list = service.list(); + for (DispatchScheme dispatchScheme : list) { + List files = fileService.getFiles(getGroupId(), dispatchScheme.getId().toString()); + dispatchScheme.setFiles(files); + } + return list; + } + + @Operation(summary = "新增") + @PostMapping("/add") + public R add(@RequestBody DispatchScheme entity) { + service.add(entity); + if(entity.getFiles() != null){ + fileService.saveFile(entity.getFiles(),getGroupId(),entity.getId().toString()); + } + service.updateEsCache(entity); + return R.ok(entity); + } + + @Operation(summary = "修改") + @PostMapping("/update") + public R update(@RequestBody DispatchScheme entity) { + entity.setUpdateTm(new Date()); + service.updateById(entity); + if(entity.getFiles() != null){ + fileService.saveFile(entity.getFiles(),getGroupId(),entity.getId().toString()); + } + service.updateEsCache(entity); + return R.ok(entity); + } + + @Operation(summary = "删除") + @GetMapping("/delete/{id}") + public R delete(@PathVariable("id") Serializable id) { + service.deleteEsCache(id); + boolean flag = service.removeById(id); + fileService.deleteFile(getGroupId(),id.toString()); + return R.ok(flag); + } + + @Operation(summary = "分页") + @PostMapping("/pageByTm") + public R> pageByTm(@RequestBody DispatchSchemeDto dto) { + Page page = service.page(dto); + for (DispatchScheme record : page.getRecords()) { + List files = fileService.getFiles(getGroupId(), record.getId().toString()); + record.setFiles(files); + } + return R.ok(page); + } + + @Override + public String getGroupId() { + return "dispatchScheme"; + } +} diff --git a/src/main/java/com/gunshi/project/ss/controller/DocReportController.java b/src/main/java/com/gunshi/project/ss/controller/DocReportController.java new file mode 100644 index 0000000..d7763fd --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/controller/DocReportController.java @@ -0,0 +1,52 @@ +package com.gunshi.project.ss.controller; + + +import com.gunshi.core.result.R; +import com.gunshi.db.dto.DateTimeRangeSo; +import com.gunshi.project.ss.service.DocCenterService; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +@Tag(name = "资料中心-数据报表") +@RestController +@RequestMapping(value = "/docReport") +public class DocReportController { + + @Autowired + private DocCenterService docCenterService; + + + @PostMapping("/groupByType") + public R> groupByType(@RequestBody DateTimeRangeSo dateTimeRangeSo){ + Map map = docCenterService.groupByType(dateTimeRangeSo); + return R.ok(map); + } + + @PostMapping("/groupByDept") + public R> groupByDept(@RequestBody DateTimeRangeSo dateTimeRangeSo){ + Map map = docCenterService.groupByDept(dateTimeRangeSo); + return R.ok(map); + } + + @PostMapping("/groupBySecret") + public R> groupBySecret(@RequestBody DateTimeRangeSo dateTimeRangeSo){ + Map map = docCenterService.groupBySecret(dateTimeRangeSo); + return R.ok(map); + } + + @PostMapping("/groupByVersion") + public R> groupByVersion(@RequestBody DateTimeRangeSo dateTimeRangeSo){ + Map map = docCenterService.groupByVersion(dateTimeRangeSo); + return R.ok(map); + } + + @PostMapping("/groupByTm") + public R> groupByTm(@RequestBody DateTimeRangeSo dateTimeRangeSo){ + Map map = docCenterService.groupByTm(dateTimeRangeSo); + return R.ok(map); + } + +} diff --git a/src/main/java/com/gunshi/project/ss/controller/ForecastProjectController.java b/src/main/java/com/gunshi/project/ss/controller/ForecastProjectController.java index d766302..507bb9d 100644 --- a/src/main/java/com/gunshi/project/ss/controller/ForecastProjectController.java +++ b/src/main/java/com/gunshi/project/ss/controller/ForecastProjectController.java @@ -8,8 +8,7 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.gunshi.core.result.R; import com.gunshi.project.ss.entity.vo.ForecastResultVo; -import com.gunshi.project.ss.model.ForecastProject; -import com.gunshi.project.ss.model.ForecastResults; +import com.gunshi.project.ss.model.*; import com.gunshi.project.ss.service.ForecastProjectService; import com.gunshi.project.ss.service.ForecastResultsService; import com.gunshi.project.ss.common.validate.markers.Insert; @@ -146,6 +145,20 @@ public class ForecastProjectController { return R.ok(result ? forecastProject : null); } + @Operation(summary = "调度计算-闸门开放关闭时间") + @GetMapping("/caculate/{waterLevel}") + public R> caculate(@PathVariable("waterLevel") String waterLevel) { + List res = service.caculate(waterLevel); + return R.ok(res); + } + + @Operation(summary = "调度计算-调度结果") + @GetMapping("/dispatch/result") + public R getDispatchResult(){ + ForecastDispatchResult result = service.getDispatchResult(); + return R.ok(result); + } + @Operation(summary = "根据方案id查看方案洪水预报结果") @GetMapping("/getForecastProjectResults") diff --git a/src/main/java/com/gunshi/project/ss/controller/GlobalSearchController.java b/src/main/java/com/gunshi/project/ss/controller/GlobalSearchController.java new file mode 100644 index 0000000..e22e74e --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/controller/GlobalSearchController.java @@ -0,0 +1,84 @@ +package com.gunshi.project.ss.controller; + + +import com.alibaba.fastjson2.JSONObject; +import com.google.common.collect.Lists; +import com.gunshi.core.result.R; +import com.gunshi.project.ss.entity.es.EsObjectDocument; +import com.gunshi.project.ss.entity.so.RealRainBaseSo; +import com.gunshi.project.ss.entity.vo.RealRainListVo; +import com.gunshi.project.ss.repository.TsgObjectRepository; +import com.gunshi.project.ss.service.RealRainService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +@RestController +@RequestMapping("/globalSearch") +@Tag(name = "知识库-全局搜索接口") +public class GlobalSearchController { + + @Autowired + private TsgObjectRepository tsgObjectRepository; + + @Autowired + private RealRainService realRainService; + + @GetMapping("findByName") + @Operation(description = "根据名称搜索") + public R> findByName(@RequestParam("name") String name) { + //reCacheRealRain(); + Sort sort = Sort.by( + Sort.Order.asc("type"), + Sort.Order.asc("name") + ); + List list = tsgObjectRepository.findByName(name,sort); + return R.ok(list); + } + + /** + * 重新缓存最近一小时的雨量站数据 + */ + private void reCacheRealRain(){ + List byType = tsgObjectRepository.findByType("雨量站"); + tsgObjectRepository.deleteAll(byType); + RealRainBaseSo realRainBaseSo = new RealRainBaseSo(); + LocalDateTime now = LocalDateTime.now(); + //设置当前时间 + realRainBaseSo.setStm(now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + //计算一小时之后时间 + LocalDateTime oneHourLater = now.plusHours(1); + realRainBaseSo.setEtm(oneHourLater.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + List realRainList = realRainService.getRealRainList(realRainBaseSo); + List list = Lists.newArrayList(); + for (RealRainListVo entity : realRainList) { + EsObjectDocument objectDocument = new EsObjectDocument(); + objectDocument.setUnionCode(entity.getStcd()); + objectDocument.setName(entity.getStnm()); + objectDocument.setType("雨量站"); + String jsonString = JSONObject.toJSONString(entity); + objectDocument.setJsonStr(jsonString); + if(entity.getLgtd() != null){ + objectDocument.setLgtd(new BigDecimal(entity.getLgtd())); + } + if(entity.getLgtd() != null){ + objectDocument.setLttd(new BigDecimal(entity.getLttd())); + } + list.add(objectDocument); + } + tsgObjectRepository.saveAll(list); + } + + + +} diff --git a/src/main/java/com/gunshi/project/ss/controller/ProjectSafetyController.java b/src/main/java/com/gunshi/project/ss/controller/ProjectSafetyController.java new file mode 100644 index 0000000..ef89a99 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/controller/ProjectSafetyController.java @@ -0,0 +1,111 @@ +package com.gunshi.project.ss.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gunshi.core.result.R; +import com.gunshi.project.ss.entity.dto.ProjectSafetyDto; +import com.gunshi.project.ss.model.FileAssociations; +import com.gunshi.project.ss.model.ProjectSafety; +import com.gunshi.project.ss.model.ProjectSafetyType; +import com.gunshi.project.ss.service.FileAssociationsService; +import com.gunshi.project.ss.service.ProjectSafetyService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author lyf + * @since 2025-07-21 + */ +@Tag(name = "工程安全知识库") +@RestController +@RequestMapping(value = "/projectSafety") +public class ProjectSafetyController extends AbstractCommonFileController { + @Autowired + private ProjectSafetyService service; + + @Autowired + private FileAssociationsService fileService; + + + @Operation(summary = "按id查询") + @GetMapping("/getById/{id}") + public ProjectSafety getById(@PathVariable("id") Serializable id) { + ProjectSafety byId = service.getOneById(id); + return byId; + } + + @Operation(summary = "新增") + @PostMapping("/add") + public R add(@RequestBody ProjectSafety entity) { + service.add(entity); + if(entity.getFiles() != null){ + fileService.saveFile(entity.getFiles(),getGroupId(),entity.getId().toString()); + } + service.updateEsCache(entity); + return R.ok(entity); + } + + @Operation(summary = "修改") + @PostMapping("/update") + public R update(@RequestBody ProjectSafety entity) { + entity.setUpdateTm(new Date()); + service.updateById(entity); + if(entity.getFiles() != null){ + fileService.saveFile(entity.getFiles(),getGroupId(),entity.getId().toString()); + } + service.updateEsCache(entity); + return R.ok(entity); + } + + @Operation(summary = "删除") + @GetMapping("/delete/{id}") + public R delete(@PathVariable("id") Serializable id) { + service.deleteEsCache(id); + fileService.deleteFile(getGroupId(),id.toString()); + boolean flag = service.removeById(id); + return R.ok(flag); + } + + @Operation(summary = "分页") + @PostMapping("/pageByTm") + public R> pageByTm(@RequestBody ProjectSafetyDto dto) { + Page result = service.page(dto); + for (ProjectSafety record : result.getRecords()) { + List files = fileService.getFiles(getGroupId(), record.getId().toString()); + record.setFiles(files); + } + return R.ok(result); + } + + + @GetMapping("/listCategory") + public R> listCategory() { + return R.ok(service.listCategory()); + } + + @GetMapping("/addCategory") + public R addCategory(@RequestParam("name") String name) { + return R.ok(service.addCategory(name)); + } + + @PostMapping("/updateCategory") + public R updateCategory(@RequestBody ProjectSafetyType entity) { + return R.ok(service.updateCategory(entity)); + } + + @GetMapping("/delCategory/{id}") + public R delCategory(@PathVariable("id") Integer id) { + return R.ok(service.delCategory(id)); + } + + @Override + public String getGroupId() { + return "projectSafety"; + } + +} diff --git a/src/main/java/com/gunshi/project/ss/entity/TimeCapacity.java b/src/main/java/com/gunshi/project/ss/entity/TimeCapacity.java new file mode 100644 index 0000000..d833c1a --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/entity/TimeCapacity.java @@ -0,0 +1,18 @@ +package com.gunshi.project.ss.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 调度计算辅助类 + */ +@Data +@AllArgsConstructor +public class TimeCapacity { + + private LocalDateTime time; + private BigDecimal capacity; // 万m³ +} diff --git a/src/main/java/com/gunshi/project/ss/entity/TimeNetWater.java b/src/main/java/com/gunshi/project/ss/entity/TimeNetWater.java new file mode 100644 index 0000000..0e2019a --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/entity/TimeNetWater.java @@ -0,0 +1,17 @@ +package com.gunshi.project.ss.entity; + +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +public class TimeNetWater { + private LocalDateTime time; + private BigDecimal netWater; + + public TimeNetWater(LocalDateTime time, BigDecimal netWater) { + this.time = time; + this.netWater = netWater; + } +} diff --git a/src/main/java/com/gunshi/project/ss/entity/es/EsObjectDocument.java b/src/main/java/com/gunshi/project/ss/entity/es/EsObjectDocument.java new file mode 100644 index 0000000..99191f7 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/entity/es/EsObjectDocument.java @@ -0,0 +1,33 @@ +package com.gunshi.project.ss.entity.es; + +import lombok.Data; +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; + +import java.math.BigDecimal; + +@Data +@Document(indexName="ss_object") +public class EsObjectDocument { + @Id // 必须添加这个注解 + private String id; // 字段名可以是id或自定义 + + @Field(type = FieldType.Text, store = true) + private String unionCode; + @Field(type = FieldType.Keyword, store = true) + private String name; + @Field(type = FieldType.Keyword, store = true) + private String type; + @Field(type = FieldType.Double, store = true) + private BigDecimal lgtd; + @Field(type = FieldType.Double, store = true) + private BigDecimal lttd; + @Field(type = FieldType.Text, store = true) + private String geojson; + + @Field(type = FieldType.Text, store = true) + private String jsonStr; + +} diff --git a/src/main/java/com/gunshi/project/ss/mapper/BusinessRuleMapper.java b/src/main/java/com/gunshi/project/ss/mapper/BusinessRuleMapper.java new file mode 100644 index 0000000..4af22bd --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/mapper/BusinessRuleMapper.java @@ -0,0 +1,12 @@ +package com.gunshi.project.ss.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gunshi.project.ss.model.BusinessRule; + + +/** + * @author lyf + * @since 2025-07-21 + */ +public interface BusinessRuleMapper extends BaseMapper { +} diff --git a/src/main/java/com/gunshi/project/ss/mapper/DispatchSchemeMapper.java b/src/main/java/com/gunshi/project/ss/mapper/DispatchSchemeMapper.java new file mode 100644 index 0000000..92c5507 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/mapper/DispatchSchemeMapper.java @@ -0,0 +1,12 @@ +package com.gunshi.project.ss.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gunshi.project.ss.model.DispatchScheme; + + +/** + * @author lyf + * @since 2025-07-21 + */ +public interface DispatchSchemeMapper extends BaseMapper { +} diff --git a/src/main/java/com/gunshi/project/ss/mapper/ProjectSafetyMapper.java b/src/main/java/com/gunshi/project/ss/mapper/ProjectSafetyMapper.java new file mode 100644 index 0000000..9ed3986 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/mapper/ProjectSafetyMapper.java @@ -0,0 +1,12 @@ +package com.gunshi.project.ss.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gunshi.project.ss.model.ProjectSafety; + +/** + * @author lyf + * @since 2025-07-21 + */ +public interface ProjectSafetyMapper extends BaseMapper { + +} diff --git a/src/main/java/com/gunshi/project/ss/mapper/ProjectSafetyTypeMapper.java b/src/main/java/com/gunshi/project/ss/mapper/ProjectSafetyTypeMapper.java new file mode 100644 index 0000000..d3ff985 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/mapper/ProjectSafetyTypeMapper.java @@ -0,0 +1,11 @@ +package com.gunshi.project.ss.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gunshi.project.ss.model.ProjectSafetyType; + +/** + * @author lyf + * @since 2025-07-21 + */ +public interface ProjectSafetyTypeMapper extends BaseMapper { +} diff --git a/src/main/java/com/gunshi/project/ss/model/BusinessRule.java b/src/main/java/com/gunshi/project/ss/model/BusinessRule.java new file mode 100644 index 0000000..8a8a3f7 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/model/BusinessRule.java @@ -0,0 +1,71 @@ +package com.gunshi.project.ss.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.gunshi.core.dateformat.DateFormatString; +import com.gunshi.project.ss.common.validate.markers.Update; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * @author lyf + * @since 2025-07-21 + */ +@Schema(description = "业务规则库") +@Data +@TableName("public.business_rule") +public class BusinessRule { + @TableId(value = "id", type = IdType.AUTO) + @Schema(description = "主键") + @NotNull(message = "id不能为空", groups = {Update.class}) + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + @TableField(value = "name",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "规则名称") + private String name; + + @TableField(value = "type",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "规则类型") + private Integer type; //水资源调度,防洪调度,工程安全,应急抢险,其他 + + @TableField(value = "tm",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "编制时间") + @JsonFormat(pattern = DateFormatString.YYYY_MM_DD, timezone = "GMT+8") + private Date tm; + + @TableField(value = "status",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "状态") + private Integer status; //0=已废弃,1=生效中 + + @TableField(value = "content",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "简介") + private String content; + + @TableField(value = "_create_tm", fill = FieldFill.INSERT,updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "创建时间") + @JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8") + private Date createTm; + + + @TableField(value = "_create_user",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "创建人") + private String createUser; + + @TableField(value = "_update_tm",fill = FieldFill.INSERT_UPDATE) + @Schema(description = "更新时间") + @JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8") + private Date updateTm; + + @TableField(exist = false) + private Integer fileCount; + + @TableField(exist = false) + private List files; +} diff --git a/src/main/java/com/gunshi/project/ss/model/DispatchScheme.java b/src/main/java/com/gunshi/project/ss/model/DispatchScheme.java new file mode 100644 index 0000000..f977910 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/model/DispatchScheme.java @@ -0,0 +1,74 @@ +package com.gunshi.project.ss.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.gunshi.core.dateformat.DateFormatString; +import com.gunshi.project.ss.common.validate.markers.Update; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * @author lyf + * @since 2025-07-21 + */ +@Schema(description = "调度方案库") +@Data +@TableName(value = "dispatch_scheme", schema = "public") +public class DispatchScheme { + @TableId(value = "id", type = IdType.AUTO) + @Schema(description = "主键") + @NotNull(message = "id不能为空", groups = {Update.class}) + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + @TableField(value = "name",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "方案名称") + private String name; + + @TableField(value = "type",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "调度类型") + private Integer type; //防洪调度,兴利调度,生态调度,应急调度,其他 + + @TableField(value = "tm",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "编制时间") + @JsonFormat(pattern = DateFormatString.YYYY_MM_DD, timezone = "GMT+8") + private Date tm; + + @TableField(value = "status",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "状态") + private Integer status; //0=已废弃,1=生效中 + + @TableField(value = "content",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "简介") + private String content; + + @TableField(value = "_create_tm", fill = FieldFill.INSERT,updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "创建时间") + @JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8") + private Date createTm; + + + @TableField(value = "_create_user",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "创建人") + private String createUser; + + @TableField(value = "_update_tm",fill = FieldFill.INSERT_UPDATE,updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "更新时间") + @JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8") + private Date updateTm; + + @TableField(exist = false) + private Integer fileCount; + + + @TableField(exist = false) + private List files; + + +} diff --git a/src/main/java/com/gunshi/project/ss/model/DocCenter.java b/src/main/java/com/gunshi/project/ss/model/DocCenter.java index 33696c2..aa25f09 100644 --- a/src/main/java/com/gunshi/project/ss/model/DocCenter.java +++ b/src/main/java/com/gunshi/project/ss/model/DocCenter.java @@ -104,7 +104,7 @@ public class DocCenter { private List files; @TableField(exist = false) - @Schema(description = "一级资料类别代码") + @Schema(description = "资料类别代码") private List CategoryCodes; } \ No newline at end of file diff --git a/src/main/java/com/gunshi/project/ss/model/ProjectSafety.java b/src/main/java/com/gunshi/project/ss/model/ProjectSafety.java new file mode 100644 index 0000000..e1c1d56 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/model/ProjectSafety.java @@ -0,0 +1,66 @@ +package com.gunshi.project.ss.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.gunshi.core.dateformat.DateFormatString; +import com.gunshi.project.ss.common.validate.markers.Update; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * @author lyf + * @since 2025-07-21 + */ +@Schema(description = "工程安全知识库") +@Data +@TableName("public.project_safety") +public class ProjectSafety { + @TableId(value = "id", type = IdType.AUTO) + @Schema(description = "主键") + @NotNull(message = "id不能为空", groups = {Update.class}) + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + @TableField(value = "name",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "标题") + private String name; + + @TableField(value = "type",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "知识库类型") + private Integer type; // + + @TableField(value = "tm",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "编制时间") + @JsonFormat(pattern = DateFormatString.YYYY_MM_DD, timezone = "GMT+8") + private Date tm; + + @TableField(value = "content",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "简介") + private String content; + + @TableField(value = "_create_tm", fill = FieldFill.INSERT,updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "创建时间") + @JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8") + private Date createTm; + + @TableField(value = "_create_user",updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "创建人") + private String createUser; + + @TableField(value = "_update_tm",fill = FieldFill.INSERT_UPDATE,updateStrategy = FieldStrategy.NOT_NULL) + @Schema(description = "更新时间") + @JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8") + private Date updateTm; + + @TableField(exist = false) + private Integer fileCount; + + @TableField(exist = false) + private List files; +} diff --git a/src/main/java/com/gunshi/project/ss/model/ProjectSafetyType.java b/src/main/java/com/gunshi/project/ss/model/ProjectSafetyType.java new file mode 100644 index 0000000..f12e554 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/model/ProjectSafetyType.java @@ -0,0 +1,28 @@ +package com.gunshi.project.ss.model; + +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 com.gunshi.project.ss.common.validate.markers.Update; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * @author lyf + * @since 2025-07-21 + */ +@Schema(description = "工程安全知识库类型") +@Data +@TableName("public.project_safety_type") +public class ProjectSafetyType { + @TableId(value = "id", type = IdType.AUTO) + @Schema(description = "主键") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Integer id; + + @TableField(value = "name") + @Schema(description = "类型名称") + private String name; +} diff --git a/src/main/java/com/gunshi/project/ss/repository/TsgObjectRepository.java b/src/main/java/com/gunshi/project/ss/repository/TsgObjectRepository.java new file mode 100644 index 0000000..5656060 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/repository/TsgObjectRepository.java @@ -0,0 +1,22 @@ +package com.gunshi.project.ss.repository; + +import com.gunshi.project.ss.entity.es.EsObjectDocument; +import org.springframework.data.domain.Sort; +import org.springframework.data.elasticsearch.annotations.Query; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; + + +import java.util.List; + +public interface TsgObjectRepository extends ElasticsearchRepository { + + @Query("{\"wildcard\": {\"name\": {\"value\": \"*?0*\", \"case_insensitive\": true}}}") + List findByName(String name, Sort sort); + + + List findByType(String type); + + + EsObjectDocument findByUnionCodeAndType(String unionCode, String type); + +} diff --git a/src/main/java/com/gunshi/project/ss/service/BusinessRuleService.java b/src/main/java/com/gunshi/project/ss/service/BusinessRuleService.java new file mode 100644 index 0000000..e5d99f7 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/service/BusinessRuleService.java @@ -0,0 +1,92 @@ +package com.gunshi.project.ss.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gunshi.project.ss.entity.dto.BusinessRuleDto; +import com.gunshi.project.ss.mapper.BusinessRuleMapper; +import com.gunshi.project.ss.model.BusinessRule; +import com.gunshi.project.ss.model.FileAssociations; +import com.gunshi.project.ss.repository.TsgObjectRepository; +import com.gunshi.project.ss.util.EsCacheUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author lyf + * @since 2025-07-21 + */ +@Service +public class BusinessRuleService extends ServiceImpl { + + @Autowired + private TsgObjectRepository tsgObjectRepository; + + @Autowired + private FileAssociationsService fileAssociationsService; + + public Page page(BusinessRuleDto dto) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + if(dto.getStm() !=null && dto.getEtm() !=null){ + queryWrapper.between("tm", dto.getStm(), dto.getEtm()); + } + if (dto.getName() != null) { + queryWrapper.like("name", dto.getName()); + } + if (dto.getType() != null) { + queryWrapper.eq("type", dto.getType()); + } + if(dto.getStatus() != null) { + queryWrapper.eq("status", dto.getStatus()); + } + int pageNumber = dto.getPageSo().getPageNumber(); + int pageSize = dto.getPageSo().getPageSize(); + queryWrapper.orderByDesc("_update_tm"); + Page pageParam = new Page<>(pageNumber, pageSize); + Page ret = page(pageParam, queryWrapper); + return ret; + } + + public BusinessRule getOneById(Serializable id) { + BusinessRule businessRule = baseMapper.selectById(id); + if(businessRule != null) { + List files = fileAssociationsService.getFiles("businessRule", businessRule.getId().toString()); + if(files == null){ + businessRule.setFiles(new ArrayList<>()); + businessRule.setFileCount(0); + }else{ + businessRule.setFileCount(files.size()); + businessRule.setFiles(files); + } + } + return businessRule; + } + + public void updateEsCache(BusinessRule businessRule) { + EsCacheUtil.updateCache(tsgObjectRepository, + businessRule, + "业务规则库", + BusinessRule::getId, + BusinessRule::getName, + null, + null, + null + ); + } + + public void deleteEsCache(Serializable id) { + EsCacheUtil.deleteEsCache(tsgObjectRepository,id.toString(),"业务规则库"); + } + + public void add(BusinessRule entity) { + entity.setId(IdWorker.getId()); + entity.setUpdateTm(new Date()); + save(entity); + } +} diff --git a/src/main/java/com/gunshi/project/ss/service/DispatchSchemeService.java b/src/main/java/com/gunshi/project/ss/service/DispatchSchemeService.java new file mode 100644 index 0000000..a792864 --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/service/DispatchSchemeService.java @@ -0,0 +1,95 @@ +package com.gunshi.project.ss.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gunshi.db.dto.PageSo; +import com.gunshi.project.ss.entity.dto.DispatchSchemeDto; +import com.gunshi.project.ss.mapper.DispatchSchemeMapper; +import com.gunshi.project.ss.model.DispatchScheme; +import com.gunshi.project.ss.model.FileAssociations; +import com.gunshi.project.ss.repository.TsgObjectRepository; +import com.gunshi.project.ss.util.EsCacheUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author lyf + * @since 2025-07-21 + */ +@Service +public class DispatchSchemeService extends ServiceImpl { + + @Autowired + private TsgObjectRepository tsgObjectRepository; + + @Autowired + private FileAssociationsService fileAssociationsService; + + public Page page(DispatchSchemeDto dto) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + if(dto.getStm() !=null && dto.getEtm() !=null){ + queryWrapper.between("tm", dto.getStm(), dto.getEtm()); + } + if (dto.getName() != null) { + queryWrapper.like("name", dto.getName()); + } + if (dto.getType() != null) { + queryWrapper.eq("type", dto.getType()); + } + if(dto.getStatus() != null){ + queryWrapper.eq("status", dto.getStatus()); + } + PageSo pageSo = dto.getPageSo(); + int pageNumber = pageSo.getPageNumber(); + int pageSize = pageSo.getPageSize(); + queryWrapper.orderByDesc("_update_tm"); + Page pageParam = new Page<>(pageNumber, pageSize); + Page ret = page(pageParam, queryWrapper); + return ret; + } + + public DispatchScheme getOneById(Serializable id) { + DispatchScheme dispatchScheme = baseMapper.selectById(id); + if(dispatchScheme != null){ + List files = fileAssociationsService.getFiles("dispatchScheme", dispatchScheme.getId().toString()); + if(files == null){ + dispatchScheme.setFiles(new ArrayList<>()); + dispatchScheme.setFileCount(0); + }else{ + dispatchScheme.setFileCount(files.size()); + dispatchScheme.setFiles(files); + } + } + return dispatchScheme; + } + + public void updateEsCache(DispatchScheme dispatchScheme) { + + EsCacheUtil.updateCache(tsgObjectRepository, + dispatchScheme, + "调度方案库", + DispatchScheme::getId, + DispatchScheme::getName, + null, + null, + null + ); + } + + public void deleteEsCache(Serializable id) { + EsCacheUtil.deleteEsCache(tsgObjectRepository,id.toString(),"调度方案库"); + } + + public void add(DispatchScheme entity) { + entity.setId(IdWorker.getId()); + entity.setUpdateTm(new Date()); + save(entity); + } +} diff --git a/src/main/java/com/gunshi/project/ss/service/DocCenterService.java b/src/main/java/com/gunshi/project/ss/service/DocCenterService.java index 81ef3f1..d1c7bf0 100644 --- a/src/main/java/com/gunshi/project/ss/service/DocCenterService.java +++ b/src/main/java/com/gunshi/project/ss/service/DocCenterService.java @@ -5,12 +5,16 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gunshi.db.dto.DateTimeRangeSo; +import com.gunshi.project.ss.common.util.LocalDateTimeConverter; import com.gunshi.project.ss.entity.so.DocCenterPageSo; import com.gunshi.project.ss.mapper.DocCenterMapper; import com.gunshi.project.ss.model.DocCategory; import com.gunshi.project.ss.model.DocCenter; +import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.system.mapper.SysDeptMapper; import com.ruoyi.system.mapper.SysUserMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -19,8 +23,8 @@ import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; @Service @Slf4j @@ -33,6 +37,9 @@ public class DocCenterService extends ServiceImpl { @Autowired private SysUserMapper sysUserMapper; + @Autowired + private SysDeptMapper sysDeptMapper; + @Autowired private DocOperateLogService docOperateLogService; @@ -180,4 +187,148 @@ public class DocCenterService extends ServiceImpl { docOperateLogService.saveLog(docCenter,2); return flag; } + + public Map groupByType(DateTimeRangeSo dateTimeRangeSo) { + Map res = new HashMap<>(); + List list = lambdaQuery() + .ge(DocCenter::getCreateTime, dateTimeRangeSo.getStart()) + .le(DocCenter::getCreateTime, dateTimeRangeSo.getEnd()).list(); + + //获取去重的所有资料分类ID + List categoryIds = list.stream().distinct().map(o -> { + return o.getDocCategoryId(); + }).collect(Collectors.toList()); + + List level3Category = docCategoryService.lambdaQuery().in(DocCategory::getId, categoryIds).list(); + + for (DocCategory docCategory : level3Category) { + long count = list.stream().filter(o -> { + return docCategory.getId().equals(o.getDocCategoryId()); + }).count(); + res.put(docCategory.getCategoryName(),count); + } + return res; + } + + public Map groupByDept(DateTimeRangeSo dateTimeRangeSo) { + List list = lambdaQuery() + .ge(DocCenter::getCreateTime, dateTimeRangeSo.getStart()) + .le(DocCenter::getCreateTime, dateTimeRangeSo.getEnd()).list(); + // 按用户ID分组,再转换到部门 + return list.stream() + .filter(doc -> doc.getUserId() != null) + .collect(Collectors.groupingBy( + DocCenter::getUserId, // 先按用户分组 + Collectors.counting() // 统计每个用户的文档数 + )) + .entrySet().stream() + .collect(Collectors.toMap( + entry -> { + // 根据用户ID获取部门名称 + Long userId = entry.getKey(); + Long userDocCount = entry.getValue(); + + SysUser user = sysUserMapper.selectUserById(userId); + if (user == null || user.getDeptId() == null) { + return "未知部门"; + } + + SysDept dept = sysDeptMapper.selectDeptById(user.getDeptId()); + return dept != null ? dept.getDeptName() : "未知部门"; + }, + Map.Entry::getValue, // 文档数量 + Long::sum // 相同部门合并 + )); + + } + + public Map groupBySecret(DateTimeRangeSo dateTimeRangeSo) { + Map res = new HashMap<>(); + List list = lambdaQuery() + .ge(DocCenter::getCreateTime, dateTimeRangeSo.getStart()) + .le(DocCenter::getCreateTime, dateTimeRangeSo.getEnd()).list(); + + List secretLevel = list.stream().distinct().map(o -> { + return o.getSecretLevel(); + }).collect(Collectors.toList()); + for (Integer level : secretLevel) { + long count = list.stream().filter(o -> o.getSecretLevel().equals(level)).count(); + if(level == 0){ + res.put("公开",count); + }else if(level == 1){ + res.put("秘密",count); + }else if(level == 2){ + res.put("机密",count); + } + } + return res; + } + + public Map groupByVersion(DateTimeRangeSo dateTimeRangeSo) { + List list = lambdaQuery() + .ge(DocCenter::getCreateTime, dateTimeRangeSo.getStart()) + .le(DocCenter::getCreateTime, dateTimeRangeSo.getEnd()) + .list(); + + return list.stream() + .filter(doc -> doc.getDocVersion() != null) // 过滤null值 + .collect(Collectors.groupingBy( + doc -> doc.getDocVersion().toString(), // 转为String作为key + Collectors.counting() + )); + } + + public Map groupByTm(DateTimeRangeSo dateTimeRangeSo) { + // 1. 查询数据 + List list = lambdaQuery() + .ge(DocCenter::getCreateTime, dateTimeRangeSo.getStart()) + .le(DocCenter::getCreateTime, dateTimeRangeSo.getEnd()) + .list(); + + // 2. 按年月分组统计 + Map grouped = list.stream() + .collect(Collectors.groupingBy( + doc -> { + LocalDateTime createTime = doc.getCreateTime(); + // 格式化为年月:2025-11 + return String.format("%d-%02d", + createTime.getYear(), + createTime.getMonthValue()); + }, + Collectors.counting() + )); + + // 3. 补全缺失的月份 + return fillMissingMonths(grouped, dateTimeRangeSo.getStart(),dateTimeRangeSo.getEnd()); + } + + /** + * 补全缺失月份的方法 + */ + private Map fillMissingMonths(Map grouped, Date startDate, Date endDate) { + Map result = new LinkedHashMap<>(); // 保持插入顺序 + + // 将Date转换为LocalDateTime + LocalDateTime start = LocalDateTimeConverter.fromDate(startDate); + LocalDateTime end = LocalDateTimeConverter.fromDate(endDate); + + // 调整到每月的第一天 + LocalDateTime current = start.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0); + LocalDateTime lastMonth = end.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0); + + // 遍历每个月份 + while (!current.isAfter(lastMonth)) { + String monthKey = String.format("%d-%02d", + current.getYear(), + current.getMonthValue()); + + // 如果有数据则取数据,否则为0 + result.put(monthKey, grouped.getOrDefault(monthKey, 0L)); + + // 下一个月 + current = current.plusMonths(1); + } + + return result; + } } diff --git a/src/main/java/com/gunshi/project/ss/service/ForecastProjectService.java b/src/main/java/com/gunshi/project/ss/service/ForecastProjectService.java index 65f7950..4b4fe01 100644 --- a/src/main/java/com/gunshi/project/ss/service/ForecastProjectService.java +++ b/src/main/java/com/gunshi/project/ss/service/ForecastProjectService.java @@ -1,11 +1,14 @@ package com.gunshi.project.ss.service; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gunshi.project.ss.common.util.LocalDateTimeConverter; +import com.gunshi.project.ss.entity.TimeCapacity; +import com.gunshi.project.ss.entity.TimeNetWater; import com.gunshi.project.ss.entity.vo.ForecastResultVo; import com.gunshi.project.ss.mapper.ForecastProjectMapper; -import com.gunshi.project.ss.model.ForecastProject; -import com.gunshi.project.ss.model.ForecastResults; +import com.gunshi.project.ss.model.*; import com.itextpdf.io.font.PdfEncodings; import com.itextpdf.kernel.colors.DeviceRgb; import com.itextpdf.kernel.events.Event; @@ -36,9 +39,12 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.stream.Collectors; import java.util.zip.ZipOutputStream; /** @@ -57,6 +63,12 @@ public class ForecastProjectService extends ServiceImpl caculate(String rz) { + BigDecimal openDoorFlow = new BigDecimal(5);//开闸门放水流量 5立方米/秒 + + ForecastTask forecastTask = new ForecastTask(); + // 设置当前时间整点 + LocalDateTime now = LocalDateTime.now(); + LocalDateTime nowHour = now.withMinute(0).withSecond(0).withNano(0); + forecastTask.setNowTime(LocalDateTimeConverter.toDate(nowHour)); + + // 设置开始时间(当前时间减去一天) + LocalDateTime startTime = nowHour.minusDays(1); + forecastTask.setStartTime(LocalDateTimeConverter.toDate(startTime)); + + // 设置结束时间(当前时间加上durationHours) + LocalDateTime endTime = nowHour.plusHours(24); + forecastTask.setEndTime(LocalDateTimeConverter.toDate(endTime)); + + forecastTask.setForecastWarm(1); + forecastTask.setForecastPeriod(24); // 设置预报时长 + List humanForecastResult = forecastResultsService.getHumanForecastResult(forecastTask); + if(humanForecastResult.isEmpty()){ + throw new IllegalArgumentException("对不起,暂无预报数据"); + } + //过滤出大于等于nowHour的数据 + // 获取当前时间的格式化字符串(与tm格式一致) + String nowHourStr = nowHour.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + // 过滤出大于等于当前时间的数据(数据已按时间tm 从小到大排序) + List filteredResults = humanForecastResult.stream() + .filter(vo -> { + if (vo.getTm() == null || vo.getTm().isEmpty()) { + return false; + } + // 字符串比较(因为格式相同,可以直接比较) + return vo.getTm().compareTo(nowHourStr) >= 0; + }) + .collect(Collectors.toList()); +// filteredResults.stream().forEach(o ->{ +// o.setYcRkQValue(new BigDecimal("10")); +// o.setYcCkQValue(new BigDecimal("0")); +// }); + ForecastResultVo forecastResultVo = filteredResults.get(0);//a点 + //b点为filteredResults的最后一条数据 + //c点为waterLevel + BigDecimal waterLevel = new BigDecimal(rz);//c点 + LocalDateTime start = null; + LocalDateTime end = null; + List stZvarlBList = stZvarlBService.list(); + // 获取配置参数 + List paramList = forecastUseparamService.list(new QueryWrapper().isNotNull("param_code").isNotNull("param_value")); + if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(paramList)) { + throw new IllegalArgumentException("温馨提示:当前洪水预报所依赖的数据尚不完整,请检查入参是否缺失。"); + } + Map paramMap = paramList.stream().collect(Collectors.toMap(ForecastUseparam::getParamCode, ForecastUseparam::getParamValue, (existing, replacement) -> existing)); + if (paramMap.get("dt").isEmpty()) { + throw new IllegalArgumentException("温馨提示:当前洪水预报所依赖的数据尚不完整,请检查时间单元△T是否缺失。"); + } + double dt = Double.parseDouble(paramMap.get("dt")); + BigDecimal timeInterval; + if(dt == 0.5){ + timeInterval = new BigDecimal("1800"); + }else{ + timeInterval = new BigDecimal("3600"); + } + if(forecastResultVo.getYcSwHValue().compareTo(waterLevel) > 0){ + //如果实际水位已经大于了输入的水位的话,那么闸门开门时间就设置为当前时间 + start = nowHour;// + //计算闸门关门时间 + //计算a点库容 + //库容单位 万m³ + BigDecimal aKR = stZvarlBService.getWByZvarl(stZvarlBList,forecastResultVo.getYcSwHValue()); + //计算c点库容 + //库容单位 万m³ + BigDecimal cKR = stZvarlBService.getWByZvarl(stZvarlBList,waterLevel); + //计算a库容 - c库容 + //库容单位 万m³ + BigDecimal aSubC = aKR.subtract(cKR);//此时库容为正 + + // 存储每个时间点的库容 + List timeCapacities = new ArrayList<>(); + + // a点的库容就是起始库容 + BigDecimal currentCapacity = aKR; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime currentTime = LocalDateTime.parse(forecastResultVo.getTm(), formatter); + timeCapacities.add(new TimeCapacity(currentTime, currentCapacity)); + // 从a点开始往后依次计算各时段末水库库容 + for (int i = 0; i < filteredResults.size() - 1; i++) { + ForecastResultVo currentVo = filteredResults.get(i); + ForecastResultVo nextVo = filteredResults.get(i + 1); + + // 获取预测入库流量和预测出库流量 + BigDecimal ycRkQValue = currentVo.getYcRkQValue() != null ? currentVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal ycCkQValue = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO; + + // 计算公式:Vt+1 = Vt + (预测入库流量 - 预测出库流量 - 5) * 时间间隔 + // 注意单位转换:流量是m³/s,库容是万m³,时间间隔是秒 + BigDecimal flowDiff = ycRkQValue.subtract(ycCkQValue).subtract(openDoorFlow); // m³/s + BigDecimal volumeChange = flowDiff.multiply(timeInterval); // m³ + + // 转换为万m³:1万m³ = 10000 m³ + BigDecimal volumeChangeInTenThousand = volumeChange.divide(new BigDecimal(10000), 10, BigDecimal.ROUND_HALF_UP); + + // 计算下一时段库容(从当前库容开始计算) + BigDecimal nextCapacity = currentCapacity.add(volumeChangeInTenThousand); + + // 获取下一时间点 + LocalDateTime nextTime = LocalDateTime.parse(nextVo.getTm(), formatter); + + // 存储时间点和对应的库容 + timeCapacities.add(new TimeCapacity(nextTime, nextCapacity)); + + // 为下一次循环更新当前库容 + currentCapacity = nextCapacity; + } + // 找到【库容最后一次(前一整点库容>c对应的库容)≤c对应的库容】所对应的时间整点d + LocalDateTime dTime = null; + + // 从后往前找,要求找到一个时间点,要求这个时间点前面第一个的库容要大于C对应库容, + // 这个时间点之后的第一个时间点的库容要小于C点对应库容 + for (int i = timeCapacities.size() - 1; i > 0; i--) { + TimeCapacity current = timeCapacities.get(i); + TimeCapacity previous = timeCapacities.get(i - 1); + + // 检查条件:当前库容 ≤ c库容 且 前一库容 > c库容 + if (current.getCapacity().compareTo(cKR) <= 0 && + previous.getCapacity().compareTo(cKR) > 0) { + dTime = current.getTime(); + break; + } + } + if(dTime == null){ + //如果a~b之间不存在d点,则闸门关闭时间 = a时间点 + [(a~b之间净入库水量) + (aSubC)] /5(先精确时分秒,向上取整,再精确到时分) + //计算净入库水量 + BigDecimal pureRKWater = BigDecimal.ZERO;//净入库水量 + for(int i =0;i 0) { + // 分钟加1 + closeTime = closeTime.plusMinutes(1); + } + // 再精确到时分(分钟和秒设为0) + closeTime = closeTime.withSecond(0).withNano(0); + end = closeTime; + }else{ + /** + * 如果存在d点 + * 那么从d点往前推算要求库容刚好<=c水位值对应的库容的具体时间点e【精确只时分,d点往前倒推时长的计算公式为(ps这个公式是用于计算e点的公式) + * (c水位值对应的库容 - d点库容 ) / (d-1的出库流量 + 5 - d-1的入库流量) 不进行四舍五入,若存在小数点则向下取证 + * 然后 计算e~b之间累计的净入库水量f f计算公式为(入库流量-出库流量)*时间间隔 求和 + * 最后计算出e点往后的持续开闸时长g = f/5 确定闸门关闭时间=e+g + */ + // 1. 找到d点在filteredResults中的索引 + int dIndex = -1; + for (int i = 0; i < filteredResults.size(); i++) { + if (filteredResults.get(i).getTm().equals(dTime.format(formatter))) { + dIndex = i; + break; + } + } + // 获取d-1点的数据 + ForecastResultVo dMinus1Vo = filteredResults.get(dIndex - 1); + // 获取d点的库容(从timeCapacities中查找) + BigDecimal dCapacity = null; + for (TimeCapacity tc : timeCapacities) { + if (tc.getTime().equals(dTime)) { + dCapacity = tc.getCapacity(); + break; + } + } + // 计算:c水位值对应的库容 - d点库容 + BigDecimal capacityDiff = cKR.subtract(dCapacity); // 万m³ + BigDecimal capacityDiffInM3 = capacityDiff.multiply(new BigDecimal("10000")); // 转换为m³ + // 获取d-1点的入库流量和出库流量 + BigDecimal dMinus1RkQ = dMinus1Vo.getYcRkQValue() != null ? dMinus1Vo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal dMinus1CkQ = dMinus1Vo.getYcCkQValue() != null ? dMinus1Vo.getYcCkQValue() : BigDecimal.ZERO; + // 计算:(d-1的出库流量 + 5 - d-1的入库流量) + BigDecimal flowRateDiff = dMinus1CkQ.add(openDoorFlow).subtract(dMinus1RkQ); // m³/s + // 防止除数为0或负数 +// if (flowRateDiff.compareTo(BigDecimal.ZERO) <= 0) { +// flowRateDiff = new BigDecimal("0.001"); // 设置一个很小的正数 +// } + // 计算往前倒推的时长:(c水位值对应的库容 - d点库容) / (d-1的出库流量 + 5 - d-1的入库流量) + BigDecimal backwardSeconds = capacityDiffInM3.divide(flowRateDiff, 10, BigDecimal.ROUND_HALF_UP); + // 不进行四舍五入,若存在小数点则向下取整 + long backwardSecondsLong = backwardSeconds.setScale(0, BigDecimal.ROUND_DOWN).longValue(); + // 计算e点时间 = d点时间 - 倒推时长 + LocalDateTime eTime = dTime.minusSeconds(backwardSecondsLong); + // 检查e点是否在filteredResults集合中存在 + boolean eTimeExists = false; + ForecastResultVo ePointVo = null; + for (ForecastResultVo vo : filteredResults) { + LocalDateTime voTime = LocalDateTime.parse(vo.getTm(), formatter); + if (voTime.equals(eTime)) { + eTimeExists = true; + ePointVo = vo; + break; + } + } + // 精确到时分(秒设为0) + eTime = eTime.withSecond(0).withNano(0); + + // 2. 计算e~b之间的净入库水量f + BigDecimal f = BigDecimal.ZERO; + + // 找到e点在filteredResults中的索引 + int eIndex = -1; + for (int i = 0; i < filteredResults.size(); i++) { + LocalDateTime voTime = LocalDateTime.parse(filteredResults.get(i).getTm(), formatter); + if (voTime.equals(eTime) || voTime.isBefore(eTime)) { // e点或之后的时间 + eIndex = i; + }else{ + break; + } + } + + if (eIndex == -1) { + eIndex = 0; // 如果没找到,从第一个开始 + } + + // 计算e~b之间的净入库水量 + for (int i = eIndex; i < filteredResults.size() - 1; i++) { + ForecastResultVo currentVo = filteredResults.get(i); + BigDecimal ycRkQValue = currentVo.getYcRkQValue() != null ? currentVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal ycCkQValue = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO; + + // (入库流量 - 出库流量) * 时间间隔 + BigDecimal gapQValue = ycRkQValue.subtract(ycCkQValue); + + if (i == eIndex) { + // 对于eIndex处的数据,使用eTime与下一条数据的时间间隔 + ForecastResultVo nextVo = filteredResults.get(i + 1); + LocalDateTime nextTime = LocalDateTime.parse(nextVo.getTm(), formatter); + + // 计算eTime到nextTime的时间差(小时) + long minutesDiff = ChronoUnit.MINUTES.between(eTime, nextTime); + BigDecimal currentTimeInterval = BigDecimal.valueOf(minutesDiff).divide(BigDecimal.valueOf(60), 10, RoundingMode.HALF_UP); + + BigDecimal timeSum = gapQValue.multiply(currentTimeInterval); + f = f.add(timeSum); + } else { + // 其他情况使用固定的timeInterval + BigDecimal timeSum = gapQValue.multiply(timeInterval); + f = f.add(timeSum); + } + } + + // 3. 计算持续开闸时长g = f / 5 + BigDecimal gSeconds = f.divide(openDoorFlow, 10, BigDecimal.ROUND_HALF_UP); + + // 不进行四舍五入,若存在小数点则向下取整 + long gSecondsLong = gSeconds.setScale(0, BigDecimal.ROUND_DOWN).longValue(); + + // 4. 计算闸门关闭时间 = e + g + LocalDateTime closeTime = eTime.plusSeconds(gSecondsLong); + + // 如果有秒数或者分钟数有小数部分(即秒数不为0),则分钟向上取整 + if (closeTime.getSecond() > 0) { + // 分钟加1 + closeTime = closeTime.plusMinutes(1); + } + closeTime = closeTime.withSecond(0).withNano(0); + end = closeTime; + } + + }else{ + //若a<=c 则判断 (a点水位对应库容 + a点 ~t点的净入库量) 与(c水位对应库容之间的大小关系 (t再a~b之间任意一点,包括a b) + //1 若任意(a点水位对应库容 + a点~t点的净入库量)均<=c点对应的库容(这里对预测数据进行遍历 一条一条对比 不是累加和的对比),则不开闸 + // 计算a点库容 + BigDecimal aKR = stZvarlBService.getWByZvarl(stZvarlBList, forecastResultVo.getYcSwHValue()); + // 计算c点库容 + BigDecimal cKR = stZvarlBService.getWByZvarl(stZvarlBList, waterLevel); + boolean needToOpenGate = false; // 是否需要开闸的标志 + // 遍历filteredResults中的每个点(从a点到b点) + for (int i = 0; i < filteredResults.size(); i++) { + // 计算从a点到当前点t的累计净入库量 + BigDecimal netInflow = BigDecimal.ZERO; + + // 注意:这里需要累加从a点到当前点t-1的净入库量 + for (int j = 0; j < i; j++) { + ForecastResultVo currentVo = filteredResults.get(j); + BigDecimal ycRkQValue = currentVo.getYcRkQValue() != null ? currentVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal ycCkQValue = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO; + + // (入库流量 - 出库流量) * 时间间隔 + BigDecimal gapQValue = ycRkQValue.subtract(ycCkQValue).subtract(openDoorFlow); + BigDecimal timeSum = gapQValue.multiply(timeInterval); + netInflow = netInflow.add(timeSum); + } + + // 计算:a点水位对应库容 + a点~t点的净入库量 + // 注意单位转换:aKR是万m³,netInflow是m³,需要统一单位 + BigDecimal netInflowInTenThousand = netInflow.divide(new BigDecimal(10000), 10, BigDecimal.ROUND_HALF_UP); + BigDecimal totalCapacityAtT = aKR.add(netInflowInTenThousand); + + // 判断:如果任意一个时间点的总库容 > c点对应的库容,则需要开闸 + if (totalCapacityAtT.compareTo(cKR) > 0) { + needToOpenGate = true; + break; // 只要有一个点超过c点库容,就需要开闸,退出循环 + } + } + if(needToOpenGate){ + //表示要开闸 + /** + * 首先 根据前面计算的a~b之间各时段末的水库库容(库容t+1 = 库容t +(入库-出库)* 时间间隔) + */ + // 存储每个时间点的库容 + List timeCapacities = new ArrayList<>(); + + // a点的库容就是起始库容 + BigDecimal currentCapacity = aKR; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime currentTime = LocalDateTime.parse(forecastResultVo.getTm(), formatter); + timeCapacities.add(new TimeCapacity(currentTime, currentCapacity)); + // 从a点开始往后依次计算各时段末水库库容 + for (int i = 0; i < filteredResults.size() - 1; i++) { + ForecastResultVo currentVo = filteredResults.get(i); + ForecastResultVo nextVo = filteredResults.get(i + 1); + + // 获取预测入库流量和预测出库流量 + BigDecimal ycRkQValue = currentVo.getYcRkQValue() != null ? currentVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal ycCkQValue = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO; + + // 计算公式:Vt+1 = Vt + (预测入库流量 - 预测出库流量 - 5) * 时间间隔 + // 注意单位转换:流量是m³/s,库容是万m³,时间间隔是秒 + BigDecimal flowDiff = ycRkQValue.subtract(ycCkQValue).subtract(openDoorFlow); // m³/s + BigDecimal volumeChange = flowDiff.multiply(timeInterval); // m³ + + // 转换为万m³:1万m³ = 10000 m³ + BigDecimal volumeChangeInTenThousand = volumeChange.divide(new BigDecimal(10000), 10, BigDecimal.ROUND_HALF_UP); + + // 计算下一时段库容(从当前库容开始计算) + BigDecimal nextCapacity = currentCapacity.add(volumeChangeInTenThousand); + + // 获取下一时间点 + LocalDateTime nextTime = LocalDateTime.parse(nextVo.getTm(), formatter); + + // 存储时间点和对应的库容 + timeCapacities.add(new TimeCapacity(nextTime, nextCapacity)); + + // 为下一次循环更新当前库容 + currentCapacity = nextCapacity; + } + //遍历从a点往后找,第一次最接近于控制水位c的库容的时间整点t(这里意味着t往后的一个整点时刻对应的水库库容>c水位对应库容); + // 然后计算t0(为刚好=c的时分点),则按t0前的第一个整点时刻t往后计算出t0【计算所得的t~t0之间的持续时长,其值不要四舍五入,向下取整,精确至时分】; + LocalDateTime tTime = null; + int tIndex = -1; + //找到最接近于c点库容的整点时间位 + for (int i = 0; i < timeCapacities.size(); i++) { + TimeCapacity currentTc = timeCapacities.get(i); + if (i < timeCapacities.size() - 1) { + TimeCapacity nextTc = timeCapacities.get(i + 1); + if (nextTc.getCapacity().compareTo(cKR) > 0) { + tTime = currentTc.getTime(); + tIndex = i; + break; + } + } + } + if(tTime != null){ + //计算t0 + BigDecimal tCapacity = timeCapacities.get(tIndex).getCapacity(); + BigDecimal capacityDiff = cKR.subtract(tCapacity); // 万m³ + BigDecimal capacityDiffInM3 = capacityDiff.multiply(new BigDecimal("10000")); + // 找到t点的预测数据 + ForecastResultVo tVo = null; + for (ForecastResultVo vo : filteredResults) { + LocalDateTime voTime = LocalDateTime.parse(vo.getTm(), formatter); + if (voTime.equals(tTime)) { + tVo = vo; + break; + } + } + if (tVo != null) { + BigDecimal tRkQ = tVo.getYcRkQValue() != null ? tVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal tCkQ = tVo.getYcCkQValue() != null ? tVo.getYcCkQValue() : BigDecimal.ZERO; + + // 计算流量差 + BigDecimal flowRateDiff = tRkQ.subtract(tCkQ).subtract(openDoorFlow); + + // 计算t到t0的持续时长 + BigDecimal durationSeconds = capacityDiffInM3.divide(flowRateDiff, 10, BigDecimal.ROUND_HALF_UP); + long durationSecondsLong = durationSeconds.setScale(0, BigDecimal.ROUND_DOWN).longValue(); + + // 计算t0时间 + LocalDateTime t0Time = tTime.plusSeconds(durationSecondsLong); + t0Time = t0Time.withSecond(0).withNano(0); + + // 设置闸门开启时间 + start = t0Time; + } + } + //假设t0为开闸时间 + if(start != null){ + //计算t0 ~X的累计净水量(x为t0~b之间任意一点),若任意t0~x之间的累计进水量均<=0,那么t0为开闸时间假设成立 + boolean t0Valid = true; + + // 找到t0时间前面第一个时间整点(t点) + LocalDateTime t0PreTime = null; + // 从filteredResults中找到时间小于start的第一个时间点 + for (int i = filteredResults.size() - 1; i >= 0; i--) { + LocalDateTime voTime = LocalDateTime.parse(filteredResults.get(i).getTm(), formatter); + if (voTime.isBefore(start)) { + t0PreTime = voTime; + break; + } + } + + if (t0PreTime != null) { + // 计算从t0点到每个后续时间点的累计净水量 + // 首先计算t0到第一个整点的时间间隔(秒) + java.time.Duration t0ToFirstInterval = java.time.Duration.between(start, tTime.plusSeconds(timeInterval.longValue())); + long t0ToFirstSeconds = t0ToFirstInterval.getSeconds(); + + // 获取t点的入库和出库流量 + ForecastResultVo tVo = filteredResults.get(tIndex); + BigDecimal tRkQ = tVo.getYcRkQValue() != null ? tVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal tCkQ = tVo.getYcCkQValue() != null ? tVo.getYcCkQValue() : BigDecimal.ZERO; + + // 计算t0到第一个整点的净水量 + BigDecimal gapQValueT0 = tRkQ.subtract(tCkQ).subtract(openDoorFlow); + BigDecimal t0ToFirstNetWater = gapQValueT0.multiply(new BigDecimal(t0ToFirstSeconds)); + + // 检查t0到第一个整点的净水量是否>0 + if (t0ToFirstNetWater.compareTo(BigDecimal.ZERO) > 0) { + t0Valid = false; + } + + // 如果t0到第一个整点的净水量<=0,继续检查后续时间段 + if (t0Valid) { + // 从tIndex+1开始检查后续时间段 + for (int i = tIndex + 1; i < filteredResults.size() - 1; i++) { + ForecastResultVo currentVo = filteredResults.get(i); + BigDecimal ycRkQValue = currentVo.getYcRkQValue() != null ? currentVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal ycCkQValue = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO; + + BigDecimal gapQValue = ycRkQValue.subtract(ycCkQValue).subtract(openDoorFlow); + BigDecimal timeSum = gapQValue.multiply(timeInterval); + + if (timeSum.compareTo(BigDecimal.ZERO) > 0) { + t0Valid = false; + break; + } + } + } + } + if (!t0Valid) { + // 如果t0假设不成立 + LocalDateTime t0Time = start; + start = null; + //那么t~b之间就至少存在一个点x,使得t0~x之间的累计净水量(此时考虑开闸) >0,则对比找出t0~x之间的累计净水量(考虑开闸)最大值所对应的时间点x0 + //可以得到t0~x0之间的累计净水量Vt~x0,再用Vt~X0/5 得到t点之前需要提前开闸的时长dt(精确至时分,存在小数点向上取整)最终得到实际开闸时间j=t0 - dt + //砸门关闭时间计算公式如下 + /** + * 若j>=a,且x0 < b ,则计算x0~b之间的净入库水量k (x0~b点之间各时段入库流量-出库流量)*时间间隔) (这里注意x0到下一跳数据的时间间隔),再计算出x0点往后的持续开闸时长L = K/5,确定闸门关闭时间X0+L + * 若j>=A,且x0 = b,则闸门关闭时间为b + */ + + // 计算t0~x之间的累计净水量(考虑开闸) + // 找到t点在filteredResults中的索引 + int tIndexInFilter = -1; + for (int i = 0; i < filteredResults.size(); i++) { + LocalDateTime voTime = LocalDateTime.parse(filteredResults.get(i).getTm(), formatter); + if (voTime.equals(tTime)) { + tIndexInFilter = i; + break; + } + } + + // 存储每个时间点的累计净水量 + List timeNetWaters = new ArrayList<>(); + BigDecimal maxNetWater = BigDecimal.ZERO; + LocalDateTime x0Time = null; + + // 计算从t点到每个后续时间点的累计净水量 + if (tIndexInFilter != -1) { + // 首先计算t0到第一个整点的净水量(考虑开闸) + // 获取t点的流量数据 + ForecastResultVo tVo = filteredResults.get(tIndexInFilter); + BigDecimal tRkQ = tVo.getYcRkQValue() != null ? tVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal tCkQ = tVo.getYcCkQValue() != null ? tVo.getYcCkQValue() : BigDecimal.ZERO; + + // 计算t0到第一个整点的净水量(考虑开闸:入库-出库-5) + BigDecimal gapQValueT0 = tRkQ.subtract(tCkQ).subtract(openDoorFlow); + + // 找到t0后面第一个整点时间 + LocalDateTime firstWholeHourAfterT = null; + for (int i = 0; i < filteredResults.size(); i++) { + LocalDateTime voTime = LocalDateTime.parse(filteredResults.get(i).getTm(), formatter); + if (voTime.isAfter(t0Time)) { + firstWholeHourAfterT = voTime; + break; + } + } + + if (firstWholeHourAfterT != null) { + long t0ToFirstSeconds = java.time.Duration.between(t0Time, firstWholeHourAfterT).getSeconds(); + BigDecimal t0ToFirstNetWater = gapQValueT0.multiply(new BigDecimal(t0ToFirstSeconds)); + + // 存储t0到第一个整点的累计净水量 + timeNetWaters.add(new TimeNetWater(firstWholeHourAfterT, t0ToFirstNetWater)); + + if (t0ToFirstNetWater.compareTo(maxNetWater) > 0) { + maxNetWater = t0ToFirstNetWater; + x0Time = firstWholeHourAfterT; + } + + // 继续计算后续时间段的累计净水量 + BigDecimal currentNetWater = t0ToFirstNetWater; + + // 找到第一个整点在filteredResults中的索引 + int firstIndex = -1; + for (int i = 0; i < filteredResults.size(); i++) { + LocalDateTime voTime = LocalDateTime.parse(filteredResults.get(i).getTm(), formatter); + if (voTime.equals(firstWholeHourAfterT)) { + firstIndex = i; + break; + } + } + + if (firstIndex != -1) { + for (int i = firstIndex; i < filteredResults.size() - 1; i++) { + ForecastResultVo currentVo = filteredResults.get(i); + BigDecimal ycRkQValue = currentVo.getYcRkQValue() != null ? currentVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal ycCkQValue = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO; + + // 考虑开闸:入库-出库-5 + BigDecimal gapQValue = ycRkQValue.subtract(ycCkQValue).subtract(openDoorFlow); + BigDecimal timeSum = gapQValue.multiply(timeInterval); + + currentNetWater = currentNetWater.add(timeSum); + + // 存储当前时间点的累计净水量 + LocalDateTime nextTime = LocalDateTime.parse(filteredResults.get(i + 1).getTm(), formatter); + timeNetWaters.add(new TimeNetWater(nextTime, currentNetWater)); + + if (currentNetWater.compareTo(maxNetWater) > 0) { + maxNetWater = currentNetWater; + x0Time = nextTime; + } + } + } + } + } + + if (x0Time != null) { + // 计算需要提前开闸的时长dt = Vt~x0 / 5 + BigDecimal dtSeconds = maxNetWater.divide(openDoorFlow, 10, BigDecimal.ROUND_HALF_UP); + + // 向上取整 + long dtSecondsLong = dtSeconds.setScale(0, BigDecimal.ROUND_UP).longValue(); + + // 计算实际开闸时间j = t0 - dt + LocalDateTime jTime = t0Time.minusSeconds(dtSecondsLong); + + // 精确到时分 + jTime = jTime.withSecond(0).withNano(0); + + // 检查j是否>=a + LocalDateTime aTime = LocalDateTime.parse(forecastResultVo.getTm(), formatter); + if ((jTime.isAfter(aTime) || jTime.equals(aTime))) { + start = jTime; + + // 判断x0与b的关系 + LocalDateTime bTime = LocalDateTime.parse(filteredResults.get(filteredResults.size() - 1).getTm(), formatter); + + if (x0Time.isBefore(bTime)) { + // 计算x0~b之间的净入库水量k(不考虑开闸) + BigDecimal k = BigDecimal.ZERO; + + // 找到x0在filteredResults中的索引 + int x0Index = -1; + for (int i = 0; i < filteredResults.size(); i++) { + LocalDateTime voTime = LocalDateTime.parse(filteredResults.get(i).getTm(), formatter); + if (voTime.equals(x0Time)) { + x0Index = i; + break; + } + } + + if (x0Index != -1) { + // 计算x0到下一个整点的时间间隔 + if (x0Index < filteredResults.size() - 1) { + LocalDateTime nextTime = LocalDateTime.parse(filteredResults.get(x0Index + 1).getTm(), formatter); + long x0ToNextSeconds = java.time.Duration.between(x0Time, nextTime).getSeconds(); + + // 获取x0点的流量数据 + ForecastResultVo x0Vo = filteredResults.get(x0Index); + BigDecimal x0RkQ = x0Vo.getYcRkQValue() != null ? x0Vo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal x0CkQ = x0Vo.getYcCkQValue() != null ? x0Vo.getYcCkQValue() : BigDecimal.ZERO; + + BigDecimal x0ToNextNet = x0RkQ.subtract(x0CkQ).multiply(new BigDecimal(x0ToNextSeconds)); + k = k.add(x0ToNextNet); + + // 计算后续时间段的净入库水量 + for (int i = x0Index + 1; i < filteredResults.size() - 1; i++) { + ForecastResultVo currentVo = filteredResults.get(i); + BigDecimal ycRkQValue = currentVo.getYcRkQValue() != null ? currentVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal ycCkQValue = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO; + + BigDecimal gapQValue = ycRkQValue.subtract(ycCkQValue); + BigDecimal timeSum = gapQValue.multiply(timeInterval); + k = k.add(timeSum); + } + } + + // 计算持续开闸时长L = k / 5 + BigDecimal LSeconds = k.divide(openDoorFlow, 10, BigDecimal.ROUND_HALF_UP); + + // 向上取整 + long LSecondsLong = LSeconds.setScale(0, BigDecimal.ROUND_UP).longValue(); + + // 计算闸门关闭时间 = x0 + L + LocalDateTime closeTime = x0Time.plusSeconds(LSecondsLong); + // 如果有秒数或者分钟数有小数部分(即秒数不为0),则分钟向上取整 + if (closeTime.getSecond() > 0) { + // 分钟加1 + closeTime = closeTime.plusMinutes(1); + } + // 精确到时分 + closeTime = closeTime.withSecond(0).withNano(0); + end = closeTime; + } + } else if (x0Time.equals(bTime)) { + // x0 = b,闸门关闭时间为b + end = bTime; + } + }else{ + //如果j < a 的情况下 + start = aTime; + //计算a~b之间的净入库水量 + BigDecimal pureRKWater = BigDecimal.ZERO; + for (int i = 0; i < filteredResults.size() -1 ; i++) { + ForecastResultVo vo = filteredResults.get(i); + BigDecimal ycRKQValue = vo.getYcRkQValue() == null?BigDecimal.ZERO:vo.getYcRkQValue(); + BigDecimal ycCKQValue = vo.getYcCkQValue() == null?BigDecimal.ZERO:vo.getYcCkQValue(); + BigDecimal gapWaterValue = ycRKQValue.subtract(ycCKQValue).multiply(timeInterval); + pureRKWater = pureRKWater.add(gapWaterValue); + } + BigDecimal openSeconds = pureRKWater.divide(openDoorFlow,10,RoundingMode.HALF_UP); + long openSecondsLong = openSeconds.setScale(0,RoundingMode.UP).longValue(); + LocalDateTime closeTime = start.plusSeconds(openSecondsLong); + end = closeTime.withSecond(0).withNano(0); + } + } + } + else{ + //如果t0假设成立,计算闸门关闭时间 + //计算t0~b之间的净入库水量h (t0~b点之间各时段入库流量-出库流量)*时间间隔),再计算出t-点往后的持续开闸时长i = h/5,确定闸门关闭时间end=i+t0 + BigDecimal h = BigDecimal.ZERO; // t0~b之间的净入库水量 + + // 找到t0后面第一个整点时间(在filteredResults中查找) + LocalDateTime firstWholeHourAfterT0 = null; + for (int i = 0; i < filteredResults.size(); i++) { + LocalDateTime voTime = LocalDateTime.parse(filteredResults.get(i).getTm(), formatter); + if (voTime.isAfter(start) || voTime.isEqual(start)) { + // 找第一个大于等于start的时间点 + firstWholeHourAfterT0 = voTime; + break; + } + } + // 计算t0到第一个整点的净入库水量 + // 获取t点的流量数据 + ForecastResultVo tVo = filteredResults.get(tIndex); + BigDecimal tRkQ = tVo.getYcRkQValue() != null ? tVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal tCkQ = tVo.getYcCkQValue() != null ? tVo.getYcCkQValue() : BigDecimal.ZERO; + // 计算t0到第一个整点的时间间隔(秒) + long t0ToFirstSeconds = java.time.Duration.between(start, firstWholeHourAfterT0).getSeconds(); + BigDecimal t0ToFirstTime = new BigDecimal(t0ToFirstSeconds); + + // 计算t0到第一个整点的净入库水量 + BigDecimal t0ToFirstNet = tRkQ.subtract(tCkQ).multiply(t0ToFirstTime); + h = h.add(t0ToFirstNet); + + // 找到第一个整点时间在filteredResults中的索引 + int firstWholeHourIndex = -1; + for (int i = 0; i < filteredResults.size(); i++) { + LocalDateTime voTime = LocalDateTime.parse(filteredResults.get(i).getTm(), formatter); + if (voTime.equals(firstWholeHourAfterT0)) { + firstWholeHourIndex = i; + break; + } + } + + // 如果找到了第一个整点,继续计算后续时间段的净入库水量 + if (firstWholeHourIndex != -1) { + for (int i = firstWholeHourIndex; i < filteredResults.size() - 1; i++) { + ForecastResultVo currentVo = filteredResults.get(i); + BigDecimal ycRkQValue = currentVo.getYcRkQValue() != null ? currentVo.getYcRkQValue() : BigDecimal.ZERO; + BigDecimal ycCkQValue = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO; + + BigDecimal gapQValue = ycRkQValue.subtract(ycCkQValue); + BigDecimal timeSum = gapQValue.multiply(timeInterval); + h = h.add(timeSum); + } + } + + // 计算持续开闸时长i = h / 5 + BigDecimal iSeconds = h.divide(openDoorFlow, 10, BigDecimal.ROUND_HALF_UP); + + // 向上取整 + long iSecondsLong = iSeconds.setScale(0, BigDecimal.ROUND_UP).longValue(); + + // 计算闸门关闭时间 = t0 + i + LocalDateTime closeTime = start.plusSeconds(iSecondsLong); + + // 如果有秒数或者分钟数有小数部分(即秒数不为0),则分钟向上取整 + if (closeTime.getSecond() > 0) { + // 分钟加1 + closeTime = closeTime.plusMinutes(1); + } + // 精确到时分(分钟和秒设为0) + closeTime = closeTime.withSecond(0).withNano(0); + end = closeTime; + } + } + } + } + if(start == null || end == null){ + return new ArrayList<>(); + } + ForecastDispatchCommand open = new ForecastDispatchCommand(); + open.setCommandTime(start); + open.setIrrigationGate(1); + open.setFloodGate(1); + ForecastDispatchCommand close = new ForecastDispatchCommand(); + close.setCommandTime(end); + close.setIrrigationGate(0); + close.setFloodGate(0); + List res = new ArrayList<>(); + res.add(open); + res.add(close); + return res; + } + + @Autowired + private AttResBaseService attResBaseService; + + public ForecastDispatchResult getDispatchResult() { + ForecastTask forecastTask = new ForecastTask(); + // 设置当前时间整点 + LocalDateTime now = LocalDateTime.now(); + LocalDateTime nowHour = now.withMinute(0).withSecond(0).withNano(0); + forecastTask.setNowTime(LocalDateTimeConverter.toDate(nowHour)); + + // 设置开始时间(当前时间减去一天) + LocalDateTime startTime = nowHour.minusDays(1); + forecastTask.setStartTime(LocalDateTimeConverter.toDate(startTime)); + + // 设置结束时间(当前时间加上durationHours) + LocalDateTime endTime = nowHour.plusHours(24); + forecastTask.setEndTime(LocalDateTimeConverter.toDate(endTime)); + + forecastTask.setForecastWarm(1); + forecastTask.setForecastPeriod(24); // 设置预报时长 + List humanForecastResult = forecastResultsService.getHumanForecastResult(forecastTask); + //过滤出大于等于nowHour的数据 + // 获取当前时间的格式化字符串(与tm格式一致) + String nowHourStr = nowHour.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + // 过滤出大于等于当前时间的数据(数据已按时间tm 从小到大排序) + List filteredResults = humanForecastResult.stream() + .filter(vo -> { + if (vo.getTm() == null || vo.getTm().isEmpty()) { + return false; + } + // 字符串比较(因为格式相同,可以直接比较) + return vo.getTm().compareTo(nowHourStr) >= 0; + }) + .collect(Collectors.toList()); + // 获取配置参数 + List paramList = forecastUseparamService.list(new QueryWrapper().isNotNull("param_code").isNotNull("param_value")); + if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(paramList)) { + throw new IllegalArgumentException("温馨提示:当前洪水预报所依赖的数据尚不完整,请检查入参是否缺失。"); + } + Map paramMap = paramList.stream().collect(Collectors.toMap(ForecastUseparam::getParamCode, ForecastUseparam::getParamValue, (existing, replacement) -> existing)); + if (paramMap.get("dt").isEmpty()) { + throw new IllegalArgumentException("温馨提示:当前洪水预报所依赖的数据尚不完整,请检查时间单元△T是否缺失。"); + } + double dt = Double.parseDouble(paramMap.get("dt")); + BigDecimal timeInterval; + if(dt == 0.5){ + timeInterval = new BigDecimal("1800"); + }else{ + timeInterval = new BigDecimal("3600"); + } + ForecastDispatchResult result = new ForecastDispatchResult(); + BigDecimal maxRKQ = BigDecimal.ZERO; + LocalDateTime maxRKDate = null; + BigDecimal totalRKWater = BigDecimal.ZERO; + BigDecimal totalCKWater = BigDecimal.ZERO; + BigDecimal maxRz = BigDecimal.ZERO; + LocalDateTime maxRzDate = null; + BigDecimal overLimit = BigDecimal.ZERO; + LocalDateTime start = null; + LocalDateTime end = null; + AttResBase attResBase = attResBaseService.list().get(0); + BigDecimal flLowLimLev = attResBase.getFlLowLimLev();//汛限水位 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + for (int i = 0; i < filteredResults.size(); i++) { + ForecastResultVo vo = filteredResults.get(i); + if(i < filteredResults.size()-1){ + //计算总入库水量和总出库水量 + BigDecimal ycRkQValue = vo.getYcRkQValue(); + BigDecimal ycCkQValue = vo.getYcCkQValue(); + ycRkQValue = ycRkQValue.multiply(timeInterval).divide(new BigDecimal("10000")).setScale(2, BigDecimal.ROUND_HALF_UP); + totalRKWater = totalRKWater.add(ycRkQValue); + ycCkQValue = ycCkQValue.multiply(timeInterval).divide(new BigDecimal("10000")).setScale(2, BigDecimal.ROUND_HALF_UP); + totalCKWater = totalCKWater.add(ycCkQValue); + } + //最高库水位 + if(vo.getYcSwHValue().compareTo(maxRz) > 0){ + maxRz = vo.getYcSwHValue(); + maxRzDate = LocalDateTime.parse(vo.getTm(),formatter); + } + //最大入库流量 + if(vo.getYcRkQValue().compareTo(maxRKQ) >0){ + maxRKQ = vo.getYcRkQValue(); + maxRKDate = LocalDateTime.parse(vo.getTm(),formatter); + } + if(start == null){ + if(vo.getYcSwHValue().compareTo(flLowLimLev) > 0){ + start = LocalDateTime.parse(vo.getTm(),formatter); + } + } + if(vo.getYcSwHValue().compareTo(flLowLimLev) > 0){ + //如果预测水位高于汛限水位 + BigDecimal gap = vo.getYcSwHValue().subtract(flLowLimLev); + if(gap.compareTo(overLimit) > 0){ + overLimit = gap; + } + + } + if(start != null && end == null){ + if(vo.getYcSwHValue().compareTo(flLowLimLev) <= 0){ + end = LocalDateTime.parse(vo.getTm(),formatter); + } + } + } + result.setMaxInflow(maxRKQ); + if(maxRKQ.compareTo(BigDecimal.ZERO) == 0){ + result.setMaxInflowDate(nowHour); + }else{ + result.setMaxInflowDate(maxRKDate); + } + result.setExceedLimitStart(start); + result.setExceedLimitEnd(end); + if(start == null && end == null){ + result.setExceedLimitValue(null); + }else{ + result.setExceedLimitValue(overLimit); + } + + result.setMaxReservoirLevel(maxRz); + result.setMaxReservoirLevelDate(maxRzDate); + + result.setTotalInflowVolume(totalRKWater); + result.setTotalOutflowVolume(totalCKWater); + return result; + } + // 页码事件处理器 - 简化版本 private static class PageNumberEventHandler implements IEventHandler { private final PdfFont font; diff --git a/src/main/java/com/gunshi/project/ss/service/JcskGnssRService.java b/src/main/java/com/gunshi/project/ss/service/JcskGnssRService.java index 8e220ba..bcf84d1 100644 --- a/src/main/java/com/gunshi/project/ss/service/JcskGnssRService.java +++ b/src/main/java/com/gunshi/project/ss/service/JcskGnssRService.java @@ -549,4 +549,8 @@ public class JcskGnssRService extends ServiceImpl { int delete = this.baseMapper.delete(queryWrapper); return delete > 0; } + + public JcskGnssR queryByCDNM(String stationCode) { + return this.baseMapper.queryByCDNM(stationCode); + } } diff --git a/src/main/java/com/gunshi/project/ss/service/JcskSlRService.java b/src/main/java/com/gunshi/project/ss/service/JcskSlRService.java index 9e89446..0025c0e 100644 --- a/src/main/java/com/gunshi/project/ss/service/JcskSlRService.java +++ b/src/main/java/com/gunshi/project/ss/service/JcskSlRService.java @@ -24,4 +24,8 @@ public class JcskSlRService extends ServiceImpl { public Page historyPage(JcskSlRPageSo page) { return this.baseMapper.historyPage(page.getPageSo().toPage(),page); } + + public JcskSlR queryByDvcd(String stationCode) { + return this.baseMapper.queryByDvcd(stationCode); + } } diff --git a/src/main/java/com/gunshi/project/ss/service/JcskSyRService.java b/src/main/java/com/gunshi/project/ss/service/JcskSyRService.java index 08aed3e..1f970d6 100644 --- a/src/main/java/com/gunshi/project/ss/service/JcskSyRService.java +++ b/src/main/java/com/gunshi/project/ss/service/JcskSyRService.java @@ -1073,4 +1073,8 @@ public class JcskSyRService extends ServiceImpl { return closestTime != null ? rzMap.get(closestTime) : BigDecimal.ZERO; } + + public JcskSyR queryByDvcd(String stationCode) { + return this.baseMapper.queryByDvcd(stationCode); + } } diff --git a/src/main/java/com/gunshi/project/ss/service/OsmoticWarnRuleService.java b/src/main/java/com/gunshi/project/ss/service/OsmoticWarnRuleService.java index 5f08131..e316b74 100644 --- a/src/main/java/com/gunshi/project/ss/service/OsmoticWarnRuleService.java +++ b/src/main/java/com/gunshi/project/ss/service/OsmoticWarnRuleService.java @@ -340,6 +340,10 @@ public class OsmoticWarnRuleService extends ServiceImpl queryStationByType(Integer type) { + return lambdaQuery().eq(OsmoticWarnRule::getType,type).list(); + } } diff --git a/src/main/java/com/gunshi/project/ss/service/ProjectSafetyService.java b/src/main/java/com/gunshi/project/ss/service/ProjectSafetyService.java new file mode 100644 index 0000000..58a665d --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/service/ProjectSafetyService.java @@ -0,0 +1,140 @@ +package com.gunshi.project.ss.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gunshi.project.ss.entity.dto.ProjectSafetyDto; +import com.gunshi.project.ss.mapper.ProjectSafetyMapper; +import com.gunshi.project.ss.mapper.ProjectSafetyTypeMapper; +import com.gunshi.project.ss.model.FileAssociations; +import com.gunshi.project.ss.model.ProjectSafety; +import com.gunshi.project.ss.model.ProjectSafetyType; +import com.gunshi.project.ss.repository.TsgObjectRepository; +import com.gunshi.project.ss.util.EsCacheUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author lyf + * @since 2025-07-21 + */ +@Service +public class ProjectSafetyService extends ServiceImpl { + @Autowired + private ProjectSafetyTypeMapper typeMapper; + + @Autowired + private TsgObjectRepository tsgObjectRepository; + + @Autowired + private FileAssociationsService fileAssociationsService; + + public List listCategory() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc("id"); + return typeMapper.selectList(queryWrapper); + } + + public Page page(ProjectSafetyDto dto) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + if(dto.getType() !=null){ + queryWrapper.eq("type", dto.getType()); + } + if(dto.getStm() !=null && dto.getEtm() !=null){ + queryWrapper.between("tm", dto.getStm(), dto.getEtm()); + } + if (dto.getName() != null) queryWrapper.like("name", dto.getName()); + int pageNumber = dto.getPageSo().getPageNumber(); + int pageSize = dto.getPageSo().getPageSize(); + queryWrapper.orderByDesc("_update_tm"); + Page pageParam = new Page<>(pageNumber,pageSize); + Page ret = page(pageParam, queryWrapper); + return ret; + } + + public ProjectSafetyType addCategory(String name) { + Long cnt = typeMapper.selectCount(new LambdaQueryWrapper().eq(ProjectSafetyType::getName, name)); + if (cnt == 0) { + ProjectSafetyType entity = new ProjectSafetyType(); + entity.setName(name); + typeMapper.insert(entity); + return entity; + }else{ + throw new IllegalArgumentException("名称重复,请检查"); + } + } + + public Boolean delCategory(Integer id) { + ProjectSafetyType type = typeMapper.selectById(id); + if (type == null) { + return false; + } + Long cnt = getBaseMapper().selectCount(new LambdaQueryWrapper().eq(ProjectSafety::getType, type.getName())); + if (cnt > 0) { + throw new IllegalArgumentException("请先删除关联数据"); + } + return typeMapper.deleteById(id) > 0; + } + + @Transactional + public Boolean updateCategory(ProjectSafetyType entity) { + ProjectSafetyType projectSafetyType = typeMapper.selectById(entity.getId()); + if (projectSafetyType == null) { + return false; + } + String oldName = projectSafetyType.getName(); + //防止重复 + Long cnt = typeMapper.selectCount(new LambdaQueryWrapper().eq(ProjectSafetyType::getName, entity.getName())); + if(cnt > 0){ + throw new IllegalArgumentException("名称重复,请检查"); + } + projectSafetyType.setName(entity.getName()); + boolean flag1 = typeMapper.updateById(projectSafetyType) > 0; + return true; + } + + public ProjectSafety getOneById(Serializable id) { + ProjectSafety projectSafety = baseMapper.selectById(id); + if(projectSafety != null){ + List files = fileAssociationsService.getFiles("projectSafety", projectSafety.getId().toString()); + if(files == null){ + projectSafety.setFiles(new ArrayList<>()); + projectSafety.setFileCount(0); + }else{ + projectSafety.setFileCount(files.size()); + projectSafety.setFiles(files); + } + } + return projectSafety; + } + + public void updateEsCache(ProjectSafety projectSafety) { + EsCacheUtil.updateCache(tsgObjectRepository, + projectSafety, + "工程安全知识库", + ProjectSafety::getId, + ProjectSafety::getName, + null, + null, + null + ); + } + + public void deleteEsCache(Serializable id) { + EsCacheUtil.deleteEsCache(tsgObjectRepository,id.toString(),"工程安全知识库"); + } + + public void add(ProjectSafety entity) { + entity.setId(IdWorker.getId()); + entity.setUpdateTm(new Date()); + save(entity); + } +} \ No newline at end of file diff --git a/src/main/java/com/gunshi/project/ss/timetask/JcskDataTask.java b/src/main/java/com/gunshi/project/ss/timetask/JcskDataTask.java index b8b09b9..f7e0add 100644 --- a/src/main/java/com/gunshi/project/ss/timetask/JcskDataTask.java +++ b/src/main/java/com/gunshi/project/ss/timetask/JcskDataTask.java @@ -2,6 +2,7 @@ package com.gunshi.project.ss.timetask; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gunshi.core.result.R; import com.gunshi.db.dto.DateTimeRangeSo; import com.gunshi.project.ss.common.model.*; import com.gunshi.project.ss.common.model.so.OsmoticQuerySo; @@ -17,15 +18,21 @@ import com.gunshi.project.ss.model.*; import com.gunshi.project.ss.service.*; import com.gunshi.project.ss.util.DateTransforUtil; import com.gunshi.project.ss.util.DateUtil; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import java.text.SimpleDateFormat; import java.time.LocalDateTime; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @@ -97,9 +104,6 @@ public class JcskDataTask { } -// /** -// * 每5分钟扫描渗流。渗压、位移表 生成预警 -// */ // @Scheduled(cron = "0 */30 * * * ?") // @Async public void syncWarn(){ @@ -117,16 +121,23 @@ public class JcskDataTask { if(gnssMaxTm==null){ gnssMaxTm = yesterday; } - List syList = jcskSyRService.lambdaQuery().gt(JcskSyR::getMstm, syMaxTm).list(); - List slList = jcskSlRService.lambdaQuery().gt(JcskSlR::getMstm, slMaxTm).list(); - List gnssList = jcskGnssRService.lambdaQuery().gt(JcskGnssR::getTm, gnssMaxTm).list(); - for (JcskSyR jcskSyR : syList) { + //只查询已配置了的测点 + List syRules = osmoticWarnRuleService.queryStationByType(PRESS); + List slRules = osmoticWarnRuleService.queryStationByType(FLOW); + List gnssRules = osmoticWarnRuleService.queryStationByType(GNSS); + for (OsmoticWarnRule syRule : syRules) { + String stationCode = syRule.getStationCode(); + JcskSyR jcskSyR = jcskSyRService.queryByDvcd(stationCode); osmoticWarnRuleService.checkWarn(jcskSyR); } - for (JcskSlR jcskSlR : slList) { + for (OsmoticWarnRule slRule : slRules) { + String stationCode = slRule.getStationCode(); + JcskSlR jcskSlR = jcskSlRService.queryByDvcd(stationCode); osmoticWarnRuleService.checkWarn(jcskSlR); } - for (JcskGnssR jcskGnssR : gnssList) { + for (OsmoticWarnRule gnssRule : gnssRules) { + String stationCode = gnssRule.getStationCode(); + JcskGnssR jcskGnssR = jcskGnssRService.queryByCDNM(stationCode); osmoticWarnRuleService.checkWarn(jcskGnssR); } } diff --git a/src/main/java/com/gunshi/project/ss/util/EsCacheUtil.java b/src/main/java/com/gunshi/project/ss/util/EsCacheUtil.java new file mode 100644 index 0000000..29b194f --- /dev/null +++ b/src/main/java/com/gunshi/project/ss/util/EsCacheUtil.java @@ -0,0 +1,140 @@ +package com.gunshi.project.ss.util; + +import com.alibaba.fastjson2.JSONObject; +import com.gunshi.project.ss.entity.es.EsObjectDocument; +import com.gunshi.project.ss.repository.TsgObjectRepository; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +public class EsCacheUtil { + + /** + * 专用于全局搜索数据缓存的删除 + * @param tsgObjectRepository + * @param id + * @param type + */ + public static void deleteEsCache(TsgObjectRepository tsgObjectRepository, + String id, + String type + ) { + EsObjectDocument byUnionCodeAndType = tsgObjectRepository.findByUnionCodeAndType(id, type); + if(byUnionCodeAndType != null){ + tsgObjectRepository.delete(byUnionCodeAndType); + } + } + + /** + * 专用于全局搜索的ES数据缓存更新 + * @param repository + * @param entitys + * @param type + * @param idGetter + * @param nameGetter + * @param lgtdGetter + * @param lttdGetter + * @param geoJsonGetter + * @param + */ + public static void updateCacheList(TsgObjectRepository repository, + List entitys, + String type, + Function idGetter, + Function nameGetter, + Function lgtdGetter, + Function lttdGetter, + Function geoJsonGetter) { + if (repository == null || entitys == null || type == null) { + return; + } + List list = new ArrayList<>(); + for (T entity : entitys) { + Object id = idGetter.apply(entity); + if (id == null) { + return; + } + + String idStr = String.valueOf(id); + EsObjectDocument query = repository.findByUnionCodeAndType(idStr, type); + if (query != null) { + repository.delete(query); + } + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(idStr); + esObjectDocument.setName(nameGetter.apply(entity)); + esObjectDocument.setType(type); + + // 处理经纬度 + esObjectDocument.setLgtd(convertCoordinate(lgtdGetter != null ? lgtdGetter.apply(entity) : null)); + esObjectDocument.setLttd(convertCoordinate(lttdGetter != null ? lttdGetter.apply(entity) : null)); + + esObjectDocument.setGeojson(geoJsonGetter != null ? (String) geoJsonGetter.apply(entity):null); + + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + + list.add(esObjectDocument); + } + repository.saveAll(list); + } + + + public static void updateCache(TsgObjectRepository repository, + T entity, + String type, + Function idGetter, + Function nameGetter, + Function lgtdGetter, + Function lttdGetter, + Function geoJsonGetter) { + if (repository == null || entity == null || type == null) { + return; + } + + Object id = idGetter.apply(entity); + if (id == null) { + return; + } + + String idStr = String.valueOf(id); + EsObjectDocument query = repository.findByUnionCodeAndType(idStr, type); + if (query != null) { + repository.delete(query); + } + EsObjectDocument esObjectDocument = new EsObjectDocument(); + esObjectDocument.setUnionCode(idStr); + esObjectDocument.setName(nameGetter.apply(entity)); + esObjectDocument.setType(type); + + // 处理经纬度 + esObjectDocument.setLgtd(convertCoordinate(lgtdGetter != null ? lgtdGetter.apply(entity) : null)); + esObjectDocument.setLttd(convertCoordinate(lttdGetter != null ? lttdGetter.apply(entity) : null)); + + esObjectDocument.setGeojson(geoJsonGetter != null ? (String) geoJsonGetter.apply(entity):null); + + String jsonString = JSONObject.toJSONString(entity); + esObjectDocument.setJsonStr(jsonString); + + repository.save(esObjectDocument); + } + + private static BigDecimal convertCoordinate(Object coordinate) { + if (coordinate == null) { + return null; + } + + if (coordinate instanceof BigDecimal) { + return (BigDecimal) coordinate; + } else if (coordinate instanceof String) { + try { + return new BigDecimal((String) coordinate); + } catch (NumberFormatException e) { + return null; + } + } + return null; + } +} diff --git a/src/main/resources/config-common.yml b/src/main/resources/config-common.yml index 8842d11..fa66930 100644 --- a/src/main/resources/config-common.yml +++ b/src/main/resources/config-common.yml @@ -16,6 +16,8 @@ mybatis-plus: update-strategy: always spring: + main: + allow-bean-definition-overriding: true servlet: multipart: max-file-size: 100MB diff --git a/src/main/resources/config-prod.yml b/src/main/resources/config-prod.yml index 872327a..a44a38a 100644 --- a/src/main/resources/config-prod.yml +++ b/src/main/resources/config-prod.yml @@ -14,12 +14,15 @@ spring: username: gunshiiot password: 1234567a driver-class-name: org.postgresql.Driver + elasticsearch: + uris: + - http://ss-es:9200 data: redis: host: ss-redis port: 6379 #password: 1234567a - database: 4 + database: 5 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl