gunshi-project-ss/deprecated/详细设计文档.md

64 KiB
Raw Blame History

黑石咀水库系统详细设计文档

第4章 项目总体设计

4.1 总体架构

4.1.1 四层分布式体系架构

黑石咀水库系统作为湖北省山洪灾害监测预报预警"四预"系统的重要组成部分,采用面向服务的架构模型,建立了完整的"基础支撑层-数据支撑层-业务支撑层-业务应用层"分布式体系架构。

架构层次设计

基础支撑层

  • 感知设备体系:集成雨量站、水位站、图像站、末端预警站等监测设备
  • 传输网络架构:水利专网和互联网双通道数据传输
  • 基础资源平台:基于省政务云水利专区的计算资源、存储资源、安全资源和资源调度服务
  • 设备接入管理:通过StPptnRStRsvrRStRiverR等实体模型实现设备数据的标准化接入

数据支撑层

  • 多源数据整合:建设汇聚库、主题库、基础库、共享库、专题库五级数据体系
  • 数据治理平台:对各类基础数据、地理空间数据、监测预报数据进行集成、存储、处理、共享
  • 数据同步机制:通过DataTaskHsz定时任务实现5分钟间隔的多源数据同步
  • 数据质量控制:实现数据清洗、验证、标准化处理

业务支撑层

  • 算法模型体系
    • 小流域分布式水文模型集成(flood_algorithm库)
    • 简化淹没范围与水深分析模型
    • GRIB2气象数据处理模型ForecastService
    • 空间数据分析模型JTS集成
  • 应用支撑平台
    • GIS引擎基于JTS的空间数据处理能力
    • 微服务管理Spring Boot 3.x原生微服务支持
    • 数据支撑平台MyBatis-Plus 3.5.7 ORM框架
    • 消息中心:MessageCenterService预警消息管理
    • 文件管理MinIO/S3兼容对象存储

业务应用层

  • 预报系统:气象预报和洪水预测功能
  • 预警系统:多级别、多类型的预警信息管理
  • 预演系统:考核评估和演练管理
  • 预案系统:应急响应和决策支持

4.1.2 技术架构实现

微服务架构设计

系统采用Spring Boot 3.x微服务架构实现服务的模块化部署和独立扩展

@GunShiApplication
@MapperScan(basePackages = {"com.gunshi.**.mapper", "com.gunshi.**.model"})
@EnableMPP
@EnableCaching
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

分层架构模式

控制器层132个REST API控制器提供统一的HTTP接口服务

  • 统一异常处理:MyE500UnknownExceptionResolver
  • 参数验证JSR-303验证注解
  • API文档Swagger 3.0自动生成

服务层:业务逻辑处理核心

  • 事务管理:@Transactional(rollbackFor = Exception.class)
  • 缓存策略:@Cacheable@CacheEvict注解
  • 异步处理:@Async@Scheduled注解

数据访问层基于MyBatis-Plus的数据持久化

  • Lambda查询类型安全的查询构建
  • 动态SQL灵活的查询条件组合
  • 分页插件:高效的数据分页处理

数据流转架构

外部数据源 → HTTP API → 数据同步任务 → 数据清洗 → PostgreSQL
    ↓
实时数据表 → 历史数据表 → 整编数据表(小时/天)
    ↓  
Redis缓存 → 业务服务调用 → 前端展示

4.2 网络架构

4.2.1 多网络区域架构设计

根据云平台整体架构规划,系统网络接入采用多区域隔离设计,包括互联网接入区、政务外网接入区,每个接入区的业务处理网络彼此隔离。

政务外网及专网区实现

网络分区设计

  • 接入区:提供专线接入湖北省水利厅专网

    • 荆楚水库APIjcskPath: http://64.97.142.113:8002/shareddata/api/v1/monitdata
    • Token认证jcskToken API访问令牌管理
    • IP白名单reloadCache动态缓存清理机制
  • 核心交换区:完成各功能分区之间数据流量的高速交换

    • 数据库主从同步PostgreSQL主备架构
    • Redis缓存集群多实例缓存服务
    • 负载均衡基于docker-compose的服务编排
  • 运维区:提供远程运维接入服务

    • SSH远程访问deploy_rsa密钥认证
    • 日志监控:应用日志和系统日志统一管理
    • 性能监控:数据库和应用性能指标监控
  • 管理区域:提供数据中心整体的管理功能

    • 用户管理基于RuoYi框架的权限管理
    • 配置管理:多环境配置文件管理
    • 审计日志:操作日志和安全审计

安全隔离区实现

容器化安全隔离

services:
  hsz:
    image: openjdk:21
    container_name: hsz
    network_mode: host
    restart: no
    volumes:
      - /root/gunshiApp/hsz:/app
    environment:
      - SPRING_PROFILES_ACTIVE=dev
      - TZ=Asia/Shanghai

网络安全配置

  • 网络模式:network_mode: host实现负载分担
  • 端口管理统一的服务端口管理24205
  • 访问控制基于Token的API访问控制

4.2.2 外部网络集成

三网接入支持

多网络接入架构

  • 电信接入通过外部API配置支持电信网络接入
  • 联通接入:多网络负载均衡和冗余设计
  • 移动接入:移动网络接入支持

外部API集成体系

# 气象数据API
shqxjsCloudowrCnPath: http://shqxjs.cloudowr.cn/service/

# 水库数据API  
owrsvrPath: http://owrsvr.cloudowr.cn/

# IP白名单管理
reloadCache: http://223.75.53.124:8002/shareddata/sys/whitelists/reloadCache

# 数据同步API
apiPath: http://223.75.53.141:8000/shzh/monitdata/datasync/getData

# 预警信息API
shqxjsWarnPath: http://223.75.53.141:8000/shzh/met/zyqxfw/api/warning/getGroupWarning

4.3 部署架构

4.3.1 容器化部署架构

前端服务器配置

VPC部署设计

  • 独立VPC环境分配弹性IP
  • 集群技术实现负载分担和高可用
  • 等保三级安全要求WAF、防DDOS、IPS等安全服务

网络优化配置

server:
  port: 24205
  servlet:
    context-path: /gunshiApp/hsz
  compression:
    enabled: true
    mime-types: application/javascript,text/css,application/json,application/xml,text/html,text/xml

后端服务器配置

独立VPC部署

  • 后端服务器在单独的VPC不分配弹性IP
  • 内部IP地址交互提高安全性
  • 云防火墙安全隔离

容器编排配置

  • 基础镜像:openjdk:21
  • 数据存储:/root/gunshiApp/hsz:/app
  • 时区配置:TZ=Asia/Shanghai
  • 环境配置:SPRING_PROFILES_ACTIVE=dev

4.3.2 数据引擎部署

PostgreSQL主备架构

主数据库配置

spring:
  datasource:
    dynamic:
      datasource:
        master:
          url: jdbc:postgresql://postgres:5432/hsz?stringtype=unspecified
          username: gunshiiot
          password: 1234567a
          driver-class-name: org.postgresql.Driver

备用数据库配置

  • 主从同步基于PostgreSQL流复制
  • 故障转移:自动主备切换机制
  • 连接池HikariCP高性能连接管理

缓存系统部署

Redis集群配置

data:
  redis:
    host: redis
    port: 6379
    database: 4

缓存策略

  • 会话管理:用户登录状态缓存
  • 查询缓存:热点数据查询优化
  • 分布式缓存:多实例数据一致性

4.4 数据架构

4.4.1 数据源体系

行业外数据源

气象数据源

  • 数据来源:省气象局气象监测雨量和预报雨量
  • 接入方式:shqxjsCloudowrCnPath API接口
  • 数据类型GRIB2气象文件、实时监测数据
  • 处理服务:ForecastService气象预报处理

水文数据源

  • 数据来源:省水文处水文监测雨量
  • 接入方式荆楚水库API专线接入
  • 数据类型:降雨量、水位、流量
  • 同步频率5分钟定时同步

水库数据源

  • 数据来源:省水库处水库监测数据
  • 接入方式:owrsvrPath API接口
  • 数据类型:水库水位、蓄水量
  • 处理机制:实时数据和历史数据分离

行业内数据源

基础地理数据

  • 数据来源中国水科院提供的107条小流域风险隐患调查数据
  • 数据类型:空间地理数据、流域边界、风险隐患要素
  • 处理方式GIS空间分析和可视化

行政区划数据

  • 数据来源:各区县水利局提供的行政区划信息
  • 数据类型:行政区划边界、责任人信息
  • 管理服务:StAddvcdDService行政区划管理

4.4.2 数据支撑平台

数据处理能力

气象文件处理

  • GRIB2文件解析grb.RainGrib2Layer网格数据模型
  • 雷达数据处理:短临预报数据处理
  • 网格计算基于JTS的空间插值算法

数据计算分析

  • 面雨量计算:泰森多边形权重计算
  • 时间序列分析:历史数据趋势分析
  • 多维分析基于MyBatis-Plus的数据统计

算法模型对接

  • 洪水算法库:flood_algorithm库集成
  • 空间分析JTS几何计算引擎
  • 预测模型:气象预报和水文预测模型

数据交换共享平台

数据同步机制

@Async
@Scheduled(fixedRate = 5, timeUnit = TimeUnit.MINUTES)
public void getPptnData() // 5分钟雨量数据同步
@Async  
@Scheduled(fixedRate = 5, timeUnit = TimeUnit.MINUTES)
public void getRiverData()  // 5分钟水情数据同步

数据汇聚中心

  • 25个县区山洪监测数据汇聚
  • 一站双发数据采集机制
  • 数据质量控制和异常处理

4.4.3 数据库体系

基础数据库设计

实体模型体系

  • 监测数据模型:StPptnRStRsvrRStRiverR
  • 预警数据模型:MessageCenterOsmoticWarnR
  • 业务数据模型:AssessTaskPrePlaceByPlan

数据关系设计

  • 一对多关系:防治对象与监测设备关系
  • 多对多关系:考核任务与考核对象关系
  • 层级关系:行政区划层级结构

专题数据库设计

预报专题库

  • 气象预报数据24小时预报和逐小时预报
  • 网格降雨数据基于GIS的空间网格数据
  • 历史比对数据:历史同期数据对比分析

预警专题库

  • 预警规则配置:OsmoticWarnRule预警规则管理
  • 预警消息记录:分级预警消息存储
  • 预警统计分析:预警频次和类型统计

4.4.4 数据应用体系

水雨情监测应用

实时监测功能

  • 实时数据展示:StPptnRRealService实时降雨监测
  • 历史数据查询:StPptnRService历史数据检索
  • 数据统计报表:多维度数据统计分析

监测站点管理

  • 站点信息管理:监测站点基本信息维护
  • 站点状态监控:设备运行状态实时监控
  • 数据质量评估:监测数据质量评估和报警

预报应用专题

天气预报功能

  • GRIB2数据处理专业气象文件解析
  • 网格降雨量计算:空间插值算法
  • 预报结果展示:多时间尺度预报展示

洪水预报功能

  • 水位预测:基于历史数据的水位预测
  • 流量预测:基于水文模型的流量预测
  • 风险评估:洪水风险评估和预警

预警应用专题

多级预警机制

  • 水位预警:超校核水位、超设计水位、超汛限水位
  • 渗压预警:渗流压力监测和预警
  • 降雨预警:强降雨监测和预警

预警消息管理

  • 消息推送:基于角色的预警消息推送
  • 状态管理:预警消息的确认和处理状态
  • 统计分析:预警数据统计和分析

4.5 安全架构

4.5.1 总体安全策略

数据安全策略

敏感数据保护

  • 数据库连接加密PostgreSQL SSL连接
  • API访问认证基于Token的身份认证
  • 密码安全:数据库密码加密存储

输入数据安全

  • XSS防护自定义Jackson反序列化器
  • SQL注入防护MyBatis-Plus参数化查询
  • 输入验证JSR-303验证注解

系统安全策略

访问控制

  • 基于角色的权限控制RuoYi框架集成
  • API访问控制Token认证机制
  • 数据访问控制:基于用户权限的数据访问

审计安全

  • 操作日志记录:用户操作行为审计
  • 系统日志监控:系统运行状态监控
  • 安全事件审计:安全事件记录和分析

4.5.2 网络安全等级保护

等保三级要求

网络安全防护

  • 网络隔离:政务外网和互联网区域隔离
  • 访问控制基于IP和端口的访问控制
  • 入侵检测:网络入侵检测和防护

数据安全防护

  • 数据加密:敏感数据传输和存储加密
  • 数据备份:定期数据备份和恢复
  • 数据完整性:数据完整性校验和验证

应用安全防护

  • 应用防火墙Web应用防火墙防护
  • 漏洞管理:定期漏洞扫描和修复
  • 安全编码:安全编码规范和检查

4.5.3 安全技术体系

计算环境安全

容器安全

  • Docker容器隔离进程和网络隔离
  • 镜像安全:基础镜像安全扫描
  • 运行时安全:容器运行时监控

应用安全

  • Spring Security安全框架集成
  • 会话管理:安全的会话管理机制
  • 异常处理:统一的异常处理机制

数据安全

  • 数据库安全PostgreSQL安全配置
  • 文件安全MinIO对象存储安全
  • 缓存安全Redis缓存安全配置

安全区域边界

网络边界安全

  • 防火墙:网络边界防火墙防护
  • 负载均衡:安全的负载均衡配置
  • DDoS防护分布式拒绝服务攻击防护

应用边界安全

  • API网关统一的API访问控制
  • 请求限流API访问频率限制
  • 参数验证:输入参数严格验证

4.5.4 安全管理体系

安全策略管理

安全策略制定

  • 数据安全策略:敏感数据保护策略
  • 网络安全策略:网络安全防护策略
  • 应用安全策略:应用系统安全策略

安全管理制度

  • 访问控制制度:基于角色的访问控制
  • 数据管理制度:数据分类和管理制度
  • 应急响应制度:安全事件应急响应流程

安全运维管理

安全监控

  • 实时监控:系统安全状态实时监控
  • 日志审计:安全日志审计和分析
  • 异常检测:安全异常行为检测

安全维护

  • 漏洞修复:定期漏洞扫描和修复
  • 安全更新:系统和应用安全更新
  • 备份恢复:数据备份和恢复演练

4.6 数据流向

4.6.1 数据采集流程

多源数据采集

山洪5分钟雨量监测数据

  • 数据源全省74个县的山洪5分钟雨量监测数据
  • 采集方式:一站双发形式,确保数据可靠性
  • 处理机制:DataTaskHsz.getPptnData()定时同步
  • 数据存储:StPptnR实时数据表和StPptnRH历史数据表

气象1小时雨量监测数据

  • 数据源省气象局Oracle数据库
  • 采集方式:先上报到省气象局,再通过数据汇集与共享平台同步
  • 处理机制GRIB2文件解析和网格化处理
  • 数据存储:ForecastService处理后的网格数据

水库1小时雨量监测数据

  • 数据源省水库处SqlServer数据库
  • 采集方式:通过数据汇集与共享平台同步
  • 处理机制:DataTaskHsz.getRiverData()定时同步
  • 数据存储:StRsvrR水库水位数据表

数据质量控制

数据验证机制

  • 完整性检查:数据字段完整性验证
  • 格式检查:数据格式和类型验证
  • 范围检查:数据值范围合理性验证

数据清洗流程

  • 异常数据处理:识别和处理异常数据
  • 重复数据去重基于时间戳和设备ID去重
  • 数据标准化:统一数据格式和单位

4.6.2 数据处理流程

实时数据处理

实时数据流入

外部API → HTTP请求 → 数据解析 → 数据验证 → PostgreSQL存储
    ↓
Redis缓存更新 → 业务服务消费 → 前端实时展示

数据同步机制

@Async
@Scheduled(fixedRate = 5, timeUnit = TimeUnit.MINUTES)
public void getPptnData() {
    // HTTP请求获取数据
    // 数据解析和验证
    // 批量保存到数据库
    // 更新Redis缓存
}

历史数据处理

数据整编处理

  • 小时数据整编基于5分钟数据生成小时统计数据
  • 天数据整编:基于小时数据生成天统计数据
  • 月数据整编:基于天数据生成月统计数据

数据归档策略

  • 实时数据保留最近30天实时数据
  • 历史数据:长期保存历史整编数据
  • 统计数据:保存各类统计数据

4.6.3 数据应用流程

业务数据应用

预报数据应用

  • 气象预报数据GRIB2文件处理和网格化展示
  • 洪水预报数据:基于水文模型的洪水预测
  • 预警数据应用:基于阈值的预警信息发布

管理数据应用

  • 考核数据管理:AssessTaskService考核任务管理
  • 防治对象管理:PrePlaceService防治点管理
  • 维护管理:MentencePlanService维护计划管理

对外数据共享

数据接口服务

  • REST API标准化的数据访问接口
  • 文件导出Excel、PDF等格式数据导出
  • 实时推送WebSocket实时数据推送

数据安全保障

  • 访问控制:基于权限的数据访问
  • 数据脱敏:敏感信息脱敏处理
  • 审计日志:数据访问日志记录

4.7 技术路线

4.7.1 微服务架构

服务拆分策略

业务模块化

  • 按业务领域划分:预报、预警、预演、预案
  • 按数据类型划分:监测数据、管理数据、统计数据
  • 按用户角色划分:管理员、县级用户、普通用户

技术组件化

  • 数据同步组件:DataTaskHsz定时任务组件
  • 预警处理组件:MessageCenterService预警消息组件
  • 预报计算组件:ForecastService气象预报组件

服务治理机制

服务注册发现

  • Spring Boot原生服务注册
  • 配置中心:多环境配置管理
  • 健康检查:服务健康状态监控

服务间通信

  • HTTP REST同步服务调用
  • 异步消息:基于消息队列的异步处理
  • 事件驱动:基于事件的松耦合架构

4.7.2 云计算技术

云平台部署

政务云集成

  • 省政务云水利专区部署
  • 专属云平台和云产品
  • 独立物理机房安全保障

容器化部署

  • Docker容器化部署
  • docker-compose服务编排
  • 持续集成和持续部署

云原生技术

微服务支持

  • Spring Boot 3.x微服务框架
  • 云原生配置管理
  • 弹性伸缩和负载均衡

DevOps实践

  • 自动化构建Maven构建工具
  • 自动化测试JUnit单元测试
  • 自动化部署:容器化部署脚本

4.8 接口设计

4.8.1 用户接口设计

REST API接口

接口标准化

  • RESTful设计符合REST架构风格
  • 统一响应格式JSON格式标准化响应
  • 错误处理:统一的异常处理机制

API文档管理

@OpenAPIDefinition(
    servers = {
        @Server(url = "http://localhost:24105/gunshiApp/hsz", description = "本地测试环境"),
        @Server(url = "http://local.gunshiiot.com:18083/gunshiApp/hsz", description = "线上测试环境")
    }
)

接口分组管理

  • 按业务模块分组:预报、预警、管理、系统
  • 按用户角色分组:管理员、县级用户、普通用户
  • 按功能类型分组:查询接口、管理接口、统计接口

前端集成接口

数据查询接口

  • 实时数据查询:/api/realtime/data
  • 历史数据查询:/api/history/data
  • 统计数据查询:/api/statistics/data

业务操作接口

  • 预警发布接口:/api/warning/publish
  • 考核管理接口:api/assessment/manage
  • 系统管理接口:/api/system/manage

4.8.2 外部接口设计

气象数据接口

GRIB2数据获取

@Value("${shqxjsCloudowrCnPath}")
private String shqxjsCloudowrCnPath;

数据处理流程

  • 文件获取从气象服务器获取GRIB2文件
  • 数据解析:解析气象网格数据
  • 结果计算:计算面雨量和预报结果

水文数据接口

荆楚水库API

@Value("${jcskPath}")
private String jcskPath; // 荆楚水库API路径

@Value("${jcskToken}")
private String jcskToken; // API访问令牌

数据同步机制

  • Token认证API访问安全认证
  • IP白名单访问IP地址控制
  • 重试机制:网络异常重试处理

4.8.3 内部接口设计

服务层接口

业务服务接口

  • 预报服务:ForecastService气象预报服务
  • 预警服务:MessageCenterService预警消息服务
  • 考核服务:AssessTaskService考核任务服务

数据服务接口

  • 实时数据服务:StPptnRRealService实时数据服务
  • 历史数据服务:StPptnRService历史数据服务
  • 统计数据服务:各种统计数据服务

数据访问接口

Mapper接口设计

  • 基础CRUD继承BaseMapper基础操作
  • 自定义查询:复杂业务查询方法
  • 动态SQL基于条件的动态查询构建

缓存接口设计

  • 查询缓存:@Cacheable查询结果缓存
  • 更新缓存:@CacheEvict缓存更新和清除
  • 分布式缓存Redis分布式缓存支持

第5章 功能设计

5.1 梳理集成基础数据

5.1.1 设计思路

为梳理集成完整的、准确的、权威的湖北山洪灾害基础数据,需对基础数据进行全量调研和评估,分析其质量、完整性、准确性,识别可能存在的数据缺失、错误或不一致等问题。

数据质量评估体系

数据完整性评估

  • 必填字段检查:确保关键字段不为空
  • 数据范围验证:验证数据在合理范围内
  • 时间连续性检查:确保时间序列数据的连续性

数据准确性评估

  • 数据一致性检查:跨表数据一致性验证
  • 业务逻辑验证:基于业务规则的逻辑验证
  • 异常值检测:识别和处理异常数据

数据权威性评估

  • 数据来源确认:确认数据来源的权威性
  • 数据更新机制:确保数据的及时更新
  • 数据版本管理:维护数据的历史版本

5.1.2 防治对象调查评价成果集成

调查评价成果数据管理

防治对象数据模型

// 防治点实体模型
public class PrePlace {
    private Long id;
    private String placeName;        // 防治点名称
    private String placeCode;        // 防治点编码
    private String placeType;        // 防治点类型
    private String location;          // 地理位置
    private String riskLevel;         // 风险等级
    // ... 其他字段
}

防治部位详细管理

// 防治部位实体模型
public class PrePlaceDetail {
    private Long id;
    private Long placeId;           // 关联防治点ID
    private String detailName;      // 部位名称
    private String detailType;      // 部位类型
    private String status;           // 状态
    // ... 其他字段
}

成果数据集成实现

调查评价成果报告管理

  • 文档存储基于MinIO的对象存储
  • 元数据管理:文档的基本信息和分类
  • 版本控制:文档版本管理和历史追踪

图集管理系统

  • 图像存储:防治对象相关图像存储
  • 空间关联:图像与防治对象的空间关联
  • 展示管理:图集的在线展示和查询

成果数据管理

  • 电子数据:结构化数据存储和管理
  • 纸质数据:纸质文档的数字化管理
  • 照片数据:相关照片的存储和管理

5.1.3 风险隐患调查与影响分析成果集成

风险隐患数据模型设计

风险隐患要素数据

// 风险隐患要素实体
public class RiskHazard {
    private Long id;
    private String hazardCode;      // 隐患编码
    private String hazardType;      // 隐患类型
    private String hazardName;      // 隐患名称
    private String location;         // 位置信息
    private String riskLevel;        // 风险等级
    private Geometry geometry;      // 空间几何信息
    // ... 其他字段
}

断面数据管理

// 断面数据实体
public class SectionData {
    private Long id;
    private String sectionCode;     // 断面编码
    private String sectionName;     // 断面名称
    private String riverCode;        // 河流编码
    private BigDecimal elevation;    // 高程
    private Geometry sectionLine;   // 断面线几何
    // ... 其他字段
}

成果报表管理实现

重点关注对象详查名录表

  • 对象管理:重点防治对象的详细信息管理
  • 风险评估:对象风险评估和等级划分
  • 监测关联:与监测设备的关联管理

防治对象-监测设备关系表

  • 关系映射:防治对象与监测设备的对应关系
  • 设备信息:监测设备的基本信息和状态
  • 数据关联:监测数据与防治对象的关联

山洪灾害防治对象名录

  • 名录管理:防治对象的统一名录管理
  • 分类管理:按类型、区域等分类管理
  • 状态管理:防治对象的状态跟踪

跨沟道路、桥涵、塘(堰)坝调查成果表

  • 设施管理:跨沟设施的管理和维护
  • 安全评估:设施安全状况评估
  • 风险分析:设施对山洪的影响分析

5.1.4 数据治理入库和应用集成

数据治理流程设计

数据提取阶段

  • 多源数据采集:从不同数据源提取原始数据
  • 数据格式转换:统一数据格式和编码
  • 数据质量检查:初步的数据质量评估

数据清洗阶段

  • 异常数据处理:识别和处理异常数据
  • 重复数据去重:基于业务规则的去重处理
  • 数据标准化:统一数据标准和规范

数据整合阶段

  • 数据关联:建立数据间的关联关系
  • 数据融合:多源数据的融合处理
  • 数据验证:业务逻辑验证和一致性检查

数据转换阶段

  • 数据映射:源数据到目标数据的映射
  • 数据计算:派生数据的计算和生成
  • 数据聚合:数据的汇总和聚合处理

数据解耦和重组阶段

  • 数据分层:按业务需求进行数据分层
  • 数据分区:按时间和区域进行数据分区
  • 数据索引:建立高效的数据索引

数据入库阶段

  • 批量导入:高效的数据批量导入
  • 事务管理:确保数据导入的事务一致性
  • 完整性检查:数据完整性和一致性验证

数据治理服务实现

数据质量监控服务

@Service
public class DataQualityService {
    
    public DataQualityReport checkDataQuality(String dataType) {
        // 数据质量检查逻辑
        return qualityReport;
    }
    
    public List<DataAnomaly> detectAnomalies(String dataset) {
        // 异常数据检测逻辑
        return anomalyList;
    }
}

数据标准化服务

@Service
public class DataStandardizationService {
    
    public StandardizedData standardizeData(RawData rawData) {
        // 数据标准化处理逻辑
        return standardizedData;
    }
    
    public ValidationResult validateStandards(StandardizedData data) {
        // 标准验证逻辑
        return validationResult;
    }
}

5.1.5 小流域治理单元建档立卡

小流域基础信息管理

小流域治理单元数据模型

// 小流域治理单元实体
public class WatershedUnit {
    private Long id;
    private String unitCode;        // 单元编码
    private String unitName;        // 单元名称
    private String area;            // 流域面积
    private String riverLength;     // 河流长度
    private String avgElevation;    // 平均高程
    private Geometry boundary;      // 流域边界
    // ... 其他字段
}

基础信息梳理功能

  • 全省1309个小流域治理单元基础信息管理
  • 流域特征参数计算和管理
  • 空间拓扑关系建立和维护

监测站点信息集成

雨量(水位)站点信息管理

// 监测站点实体
public class MonitoringStation {
    private Long id;
    private String stationCode;     // 站点编码
    private String stationName;     // 站点名称
    private String stationType;     // 站点类型
    private BigDecimal longitude;   // 经度
    private BigDecimal latitude;    // 纬度
    private Geometry location;      // 空间位置
    // ... 其他字段
}

站点关联管理

  • 空间关联:监测站点与小流域的空间关联
  • 数据关联:监测数据与小流域的数据关联
  • 状态监控:监测站点运行状态监控

降雨预报成果数据集成

网格化降雨预报数据

// 降雨预报网格数据实体
public class RainfallGrid {
    private Long id;
    private String gridCode;        // 网格编码
    private BigDecimal rainfall;    // 降雨量
    private String forecastTime;    // 预报时间
    private Integer forecastHour;   // 预报小时数
    private Geometry gridGeometry;  // 网格几何
    // ... 其他字段
}

预报成果管理功能

  • 网格数据存储和管理
  • 时间序列预报数据管理
  • 空间插值和计算功能

流域关系管理

流域拓扑关系建立

@Service
public class WatershedRelationService {
    
    public WatershedTopology buildTopology(List<WatershedUnit> units) {
        // 构建流域拓扑关系
        return topology;
    }
    
    public List<WatershedUnit> getUpstreamUnits(Long unitId) {
        // 获取上游流域单元
        return upstreamUnits;
    }
    
    public List<WatershedUnit> getDownstreamUnits(Long unitId) {
        // 获取下游流域单元
        return downstreamUnits;
    }
}

空间分析算法

  • 河流网络提取基于DEM数据的河流网络提取
  • 流域边界识别:小流域边界的自动识别
  • 拓扑关系生成:上下游关系的自动生成

5.2 算法模型建设方案

5.2.1 模型建模范围确定

小流域设计暴雨计算

暴雨参数计算模型

@Service
public class DesignStormService {
    
    public DesignStormResult calculateDesignStorm(String watershedCode, 
            int returnPeriod) {
        // 基于《湖北省暴雨统计参数等值线图集》计算设计暴雨
        DesignStormResult result = new DesignStormResult();
        
        // 计算标准历时点雨量均值
        BigDecimal tenMinMean = calculate10MinMean(watershedCode);
        BigDecimal oneHourMean = calculate1HourMean(watershedCode);
        BigDecimal sixHourMean = calculate6HourMean(watershedCode);
        BigDecimal twentyFourHourMean = calculate24HourMean(watershedCode);
        
        // 计算设计暴雨
        result.setTenMinDesign(calculateDesignRainfall(tenMinMean, returnPeriod));
        result.setOneHourDesign(calculateDesignRainfall(oneHourMean, returnPeriod));
        result.setSixHourDesign(calculateDesignRainfall(sixHourMean, returnPeriod));
        result.setTwentyFourHourDesign(calculateDesignRainfall(twentyFourHourMean, returnPeriod));
        
        return result;
    }
    
    private BigDecimal calculateDesignRainfall(BigDecimal mean, int returnPeriod) {
        // 设计暴雨计算逻辑
        return mean.multiply(getFrequencyFactor(returnPeriod));
    }
}

暴雨时程分配模型

  • 时程分配模式:基于典型暴雨过程的时程分配
  • 时间步长处理:按小时或更小时间步长分配
  • 空间分布:考虑暴雨空间分布的不均匀性

小流域设计洪水计算

净雨计算模型

@Service
public class NetRainfallService {
    
    public List<NetRainfall> calculateNetRainfall(DesignStormResult designStorm, 
            WatershedUnit watershed) {
        // 净雨计算逻辑
        List<NetRainfall> netRainfallList = new ArrayList<>();
        
        // 初损计算
        BigDecimal initialLoss = calculateInitialLoss(watershed);
        
        // 下渗计算
        BigDecimal infiltrationRate = calculateInfiltrationRate(watershed);
        
        // 净雨过程计算
        for (StormData stormData : designStorm.getStormData()) {
            NetRainfall netRainfall = new NetRainfall();
            netRainfall.setTime(stormData.getTime());
            netRainfall.setGrossRainfall(stormData.getRainfall());
            netRainfall.setNetRainfall(calculateNetAmount(
                stormData.getRainfall(), initialLoss, infiltrationRate));
            netRainfallList.add(netRainfall);
        }
        
        return netRainfallList;
    }
}

单位线法洪水计算

@Service
public class UnitHydrographService {
    
    public FloodHydrograph calculateFloodHydrograph(List<NetRainfall> netRainfall, 
            WatershedUnit watershed) {
        // 单位线法洪水计算
        FloodHydrograph hydrograph = new FloodHydrograph();
        
        // 获取单位线
        UnitHydrograph unitHydrograph = getUnitHydrograph(watershed.getUnitCode());
        
        // 卷积计算
        List<BigDecimal> discharge = new ArrayList<>();
        for (int i = 0; i < netRainfall.size(); i++) {
            BigDecimal q = BigDecimal.ZERO;
            for (int j = 0; j <= i; j++) {
                q = q.add(netRainfall.get(j).getNetRainfall()
                    .multiply(unitHydrograph.getOrdinate(i - j)));
            }
            discharge.add(q);
        }
        
        hydrograph.setDischarge(discharge);
        return hydrograph;
    }
}

经验公式法洪水计算

@Service
public class EmpiricalFormulaService {
    
    public BigDecimal calculatePeakDischarge(WatershedUnit watershed, 
            int returnPeriod) {
        // 经验公式法计算洪峰流量
        BigDecimal area = new BigDecimal(watershed.getArea());
        BigDecimal coefficient = getCoefficient(watershed, returnPeriod);
        BigDecimal exponent = getExponent(watershed);
        
        // Q = C * A^n
        return coefficient.multiply(area.pow(exponent));
    }
    
    private BigDecimal getCoefficient(WatershedUnit watershed, int returnPeriod) {
        // 根据水文分区和重现期获取系数
        return coefficientRepository.findByWatershedAndReturnPeriod(
            watershed.getHydrologicalZone(), returnPeriod);
    }
}

HEC-RAS二维水动力学模型

淹没范围分析模型

@Service
public class InundationAnalysisService {
    
    public InundationResult analyzeInundation(WatershedUnit watershed, 
            FloodHydrograph hydrograph, int returnPeriod) {
        // HEC-RAS二维水动力学模型调用
        InundationResult result = new InundationResult();
        
        // 模型输入准备
        ModelInput input = prepareModelInput(watershed, hydrograph);
        
        // 调用HEC-RAS模型
        ModelOutput output = callHECRASModel(input);
        
        // 结果处理
        result.setInundationArea(output.getInundationArea());
        result.setMaxDepth(output.getMaxDepth());
        result.setInundationMap(output.getInundationMap());
        result.setVelocityMap(output.getVelocityMap());
        
        return result;
    }
    
    private ModelOutput callHECRASModel(ModelInput input) {
        // 调用HEC-RAS模型的实现
        // 这里可以集成外部HEC-RAS计算引擎
        return hcrasEngine.run(input);
    }
}

不同重现期洪水分析

  • 50年一遇洪水中等风险洪水淹没分析
  • 100年一遇洪水高风险洪水淹没分析
  • 300年一遇洪水极高风险洪水淹没分析

5.2.2 小流域分布式水文模型精细建模

小流域计算单元划分

计算单元属性提取

@Service
public class CalculationUnitService {
    
    public List<CalculationUnit> divideCalculationUnits(WatershedUnit watershed) {
        // 小流域计算单元划分
        List<CalculationUnit> units = new ArrayList<>();
        
        // 基于DEM数据进行单元划分
        List<Subcatchment> subcatchments = extractSubcatchments(watershed);
        
        for (Subcatchment subcatchment : subcatchments) {
            CalculationUnit unit = new CalculationUnit();
            unit.setUnitCode(generateUnitCode(subcatchment));
            unit.setArea(subcatchment.getArea());
            unit.setAvgSlope(calculateAvgSlope(subcatchment));
            unit.setFlowLength(calculateFlowLength(subcatchment));
            unit.setCentroid(subcatchment.getCentroid());
            unit.setBoundary(subcatchment.getBoundary());
            
            // 提取其他属性
            unit.setLandUseType(extractLandUseType(subcatchment));
            unit.setSoilType(extractSoilType(subcatchment));
            unit.setVegetationCover(extractVegetationCover(subcatchment));
            
            units.add(unit);
        }
        
        return units;
    }
    
    private BigDecimal calculateAvgSlope(Subcatchment subcatchment) {
        // 基于DEM计算平均坡度
        return demAnalyzer.calculateAvgSlope(subcatchment);
    }
    
    private BigDecimal calculateFlowLength(Subcatchment subcatchment) {
        // 计算流径长度
        return flowAnalyzer.calculateFlowLength(subcatchment);
    }
}

小流域统一编码

@Service
public class WatershedCodingService {
    
    public String generateWatershedCode(WatershedUnit watershed) {
        // 小流域统一编码生成
        StringBuilder code = new StringBuilder();
        
        // 省级编码
        code.append("42"); // 湖北省编码
        
        // 市级编码
        code.append(String.format("%02d", watershed.getCityCode()));
        
        // 县级编码
        code.append(String.format("%02d", watershed.getCountyCode()));
        
        // 流域编码
        code.append(String.format("%03d", watershed.getRiverBasinCode()));
        
        // 小流域编码
        code.append(String.format("%04d", watershed.getUnitNumber()));
        
        return code.toString();
    }
}

面雨量权重值计算

泰森多边形权重计算

@Service
public class ThiessenPolygonService {
    
    public Map<String, BigDecimal> calculateThiessenWeights(
            List<MonitoringStation> stations, WatershedUnit watershed) {
        // 泰森多边形权重计算
        Map<String, BigDecimal> weights = new HashMap<>();
        
        // 创建泰森多边形
        List<Polygon> thiessenPolygons = createThiessenPolygons(stations);
        
        // 计算每个站点在流域内的权重
        Geometry watershedBoundary = watershed.getBoundary();
        for (int i = 0; i < stations.size(); i++) {
            Polygon stationPolygon = thiessenPolygons.get(i);
            
            // 计算站点多边形与流域的交集
            Geometry intersection = stationPolygon.intersection(watershedBoundary);
            
            // 计算权重
            BigDecimal stationArea = new BigDecimal(intersection.getArea());
            BigDecimal watershedArea = new BigDecimal(watershedBoundary.getArea());
            BigDecimal weight = stationArea.divide(watershedArea, 8, RoundingMode.HALF_UP);
            
            weights.put(stations.get(i).getStationCode(), weight);
        }
        
        return weights;
    }
    
    private List<Polygon> createThiessenPolygons(List<MonitoringStation> stations) {
        // 创建泰森多边形
        // 使用JTS的Voronoi图算法
        GeometryFactory geometryFactory = new GeometryFactory();
        
        // 创建站点点集
        Coordinate[] coordinates = stations.stream()
            .map(station -> station.getLocation().getCoordinate())
            .toArray(Coordinate[]::new);
        
        // 生成Voronoi图
        VoronoiDiagramBuilder voronoiBuilder = new VoronoiDiagramBuilder();
        voronoiBuilder.setSites(coordinates);
        Geometry voronoiDiagram = voronoiBuilder.getDiagram(geometryFactory);
        
        // 提取多边形
        return extractPolygons(voronoiDiagram);
    }
}

反距离权重插值

@Service
public class IDWInterpolationService {
    
    public Map<String, BigDecimal> calculateIDWWeights(
            List<MonitoringStation> stations, WatershedUnit watershed) {
        // 反距离权重插值
        Map<String, BigDecimal> weights = new HashMap<>();
        
        // 生成流域内网格点
        List<Coordinate> gridPoints = generateGridPoints(watershed);
        
        for (Coordinate gridPoint : gridPoints) {
            BigDecimal totalWeight = BigDecimal.ZERO;
            BigDecimal weightedRainfall = BigDecimal.ZERO;
            
            // 计算每个站点对网格点的权重
            for (MonitoringStation station : stations) {
                BigDecimal distance = calculateDistance(gridPoint, 
                    station.getLocation().getCoordinate());
                
                // 避免除零错误
                if (distance.compareTo(BigDecimal.ZERO) == 0) {
                    distance = new BigDecimal("0.0001");
                }
                
                // 权重 = 1 / distance^2
                BigDecimal weight = BigDecimal.ONE.divide(
                    distance.pow(2), 8, RoundingMode.HALF_UP);
                
                totalWeight = totalWeight.add(weight);
                weightedRainfall = weightedRainfall.add(
                    weight.multiply(station.getCurrentRainfall()));
            }
            
            // 计算网格点降雨量
            BigDecimal gridRainfall = weightedRainfall.divide(totalWeight, 
                2, RoundingMode.HALF_UP);
            
            weights.put(getGridPointCode(gridPoint), gridRainfall);
        }
        
        return weights;
    }
}

蒸散发量计算

潜在蒸散发计算

@Service
public class EvapotranspirationService {
    
    public BigDecimal calculatePET(EtData data) {
        // 潜在蒸散发计算Penman-Monteith方程
        BigDecimal delta = calculateSlopeVaporPressure(data.getTemperature());
        BigDecimal gamma = calculatePsychrometricConstant(data.getPressure());
        BigDecimal u2 = data.getWindSpeed();
        BigDecimal es = calculateSaturationVaporPressure(data.getTemperature());
        BigDecimal ea = calculateActualVaporPressure(data.getTemperature(), 
            data.getRelativeHumidity());
        
        BigDecimal rn = data.getNetRadiation();
        BigDecimal g = data.getSoilHeatFlux();
        
        // Penman-Monteith方程
        BigDecimal numerator = delta.multiply(rn.subtract(g))
            .add(K_CONSTANT.multiply(rho_AIR.multiply(CP_AIR).multiply(u2)
                .multiply(es.subtract(ea))));
        
        BigDecimal denominator = delta.add(gamma.multiply(
            BigDecimal.ONE.add(C_D_CONSTANT.multiply(u2))));
        
        return numerator.divide(denominator, 2, RoundingMode.HALF_UP);
    }
    
    private BigDecimal calculateSlopeVaporPressure(BigDecimal temperature) {
        // 饱和水汽压斜率计算
        BigDecimal temp = temperature.add(BigDecimal.valueOf(237.3));
        BigDecimal numerator = BigDecimal.valueOf(4098).multiply(
            BigDecimal.valueOf(0.6108).multiply(
                BigDecimal.valueOf(17.27).multiply(temperature).divide(temp, 
                    8, RoundingMode.HALF_UP).exp()));
        BigDecimal denominator = temp.pow(2);
        return numerator.divide(denominator, 8, RoundingMode.HALF_UP);
    }
}

实际蒸散发计算

public BigDecimal calculateAET(BigDecimal pet, BigDecimal soilMoisture, 
        BigDecimal fieldCapacity) {
    // 实际蒸散发计算
    BigDecimal moistureRatio = soilMoisture.divide(fieldCapacity, 
        8, RoundingMode.HALF_UP);
    
    if (moistureRatio.compareTo(BigDecimal.ONE) >= 0) {
        return pet; // 土壤水分充足,实际蒸散发等于潜在蒸散发
    } else {
        // 土壤水分不足,按比例减少
        return pet.multiply(moistureRatio);
    }
}

产流模型参数确定

SCS-CN产流模型

@Service
public class SCSModelService {
    
    public BigDecimal calculateSCSRunoff(BigDecimal rainfall, 
            BigDecimal cn, BigDecimal initialAbstraction) {
        // SCS-CN产流模型
        BigDecimal s = BigDecimal.valueOf(25400).divide(cn, 
            8, RoundingMode.HALF_UP).subtract(BigDecimal.valueOf(254));
        
        BigDecimal ia = initialAbstraction.multiply(s);
        
        if (rainfall.compareTo(ia) <= 0) {
            return BigDecimal.ZERO; // 降雨小于初损,无产流
        }
        
        BigDecimal numerator = rainfall.subtract(ia).pow(2);
        BigDecimal denominator = rainfall.subtract(ia).add(s);
        
        return numerator.divide(denominator, 2, RoundingMode.HALF_UP);
    }
    
    public BigDecimal calculateCNValue(LandUseType landUse, SoilType soil, 
            BigDecimal antecedentMoisture) {
        // CN值计算
        // 基于土地利用类型、土壤类型和前期湿度条件
        return cnTableRepository.findByLandUseAndSoil(landUse, soil, antecedentMoisture);
    }
}

Green-Ampt渗透模型

@Service
public class GreenAmptService {
    
    public BigDecimal calculateInfiltration(BigDecimal time, BigDecimal initialMoisture,
            BigDecimal saturatedMoisture, BigDecimal hydraulicConductivity,
            BigDecimal suctionHead, BigDecimal cumulativeInfiltration) {
        // Green-Ampt渗透模型
        BigDecimal thetaS = saturatedMoisture;
        BigDecimal thetaI = initialMoisture;
        BigDecimal deltaTheta = thetaS.subtract(thetaI);
        
        BigDecimal Ks = hydraulicConductivity;
        BigDecimal psi = suctionHead;
        BigDecimal F = cumulativeInfiltration;
        
        // Green-Ampt方程
        BigDecimal numerator = Ks.multiply(time).multiply(deltaTheta).multiply(psi).add(F);
        BigDecimal denominator = F.add(Ks.multiply(time).multiply(deltaTheta));
        
        BigDecimal newF = numerator.divide(denominator, 8, RoundingMode.HALF_UP);
        
        return newF.subtract(F); // 当前时段渗透量
    }
}

单位线提取

瞬时单位线计算

@Service
public class InstantaneousUnitHydrographService {
    
    public List<BigDecimal> calculateIUH(WatershedUnit watershed, 
            List<CalculationUnit> units) {
        // 瞬时单位线计算
        List<BigDecimal> iuh = new ArrayList<>();
        
        // 计算流域特征参数
        BigDecimal avgSlope = calculateAvgSlope(units);
        BigDecimal avgFlowLength = calculateAvgFlowLength(units);
        BigDecimal avgVelocity = calculateAvgVelocity(avgSlope);
        
        // 计算汇流时间
        BigDecimal tc = avgFlowLength.divide(avgVelocity, 
            8, RoundingMode.HALF_UP);
        
        // Nash瞬时单位线模型
        int n = 2; // 线性水库数
        BigDecimal k = tc.divide(BigDecimal.valueOf(n), 
            8, RoundingMode.HALF_UP); // 水库蓄量常数
        
        // 生成单位线纵坐标
        for (int t = 0; t < 100; t++) {
            BigDecimal ordinate = calculateNashIUHOrdinate(t, n, k);
            iuh.add(ordinate);
        }
        
        return iuh;
    }
    
    private BigDecimal calculateNashIUHOrdinate(int t, int n, BigDecimal k) {
        // Nash瞬时单位线纵坐标计算
        if (t == 0) return BigDecimal.ZERO;
        
        BigDecimal numerator = BigDecimal.ONE.pow(n - 1);
        BigDecimal denominator = BigDecimal.valueOf(factorial(n - 1))
            .multiply(k.pow(n));
        
        BigDecimal timeTerm = BigDecimal.valueOf(t).pow(n - 1);
        BigDecimal expTerm = BigDecimal.valueOf(-t).divide(k, 
            8, RoundingMode.HALF_UP).exp();
        
        return numerator.multiply(timeTerm).multiply(expTerm).divide(denominator, 
            8, RoundingMode.HALF_UP);
    }
}

河道演进模型参数确定

马斯京根法河道演进

@Service
public class MuskingumRoutingService {
    
    public List<BigDecimal> routeFloodWave(List<BigDecimal> inflow, 
            BigDecimal k, BigDecimal x, BigDecimal dt) {
        // 马斯京根法河道演进
        List<BigDecimal> outflow = new ArrayList<>();
        
        // 计算演进系数
        BigDecimal c0 = calculateC0(k, x, dt);
        BigDecimal c1 = calculateC1(k, x, dt);
        BigDecimal c2 = calculateC2(k, x, dt);
        
        // 初始条件
        outflow.add(inflow.get(0)); // 假设初始出流等于入流
        
        // 演进计算
        for (int i = 1; i < inflow.size(); i++) {
            BigDecimal qOut = c0.multiply(inflow.get(i))
                .add(c1.multiply(inflow.get(i - 1)))
                .add(c2.multiply(outflow.get(i - 1)));
            
            outflow.add(qOut);
        }
        
        return outflow;
    }
    
    private BigDecimal calculateC0(BigDecimal k, BigDecimal x, BigDecimal dt) {
        BigDecimal denominator = k.multiply(BigDecimal.valueOf(2).multiply(x).subtract(BigDecimal.ONE))
            .add(dt);
        return dt.subtract(k.multiply(x)).divide(denominator, 
            8, RoundingMode.HALF_UP);
    }
    
    private BigDecimal calculateC1(BigDecimal k, BigDecimal x, BigDecimal dt) {
        BigDecimal denominator = k.multiply(BigDecimal.valueOf(2).multiply(x).subtract(BigDecimal.ONE))
            .add(dt);
        return dt.add(k.multiply(x)).divide(denominator, 
            8, RoundingMode.HALF_UP);
    }
    
    private BigDecimal calculateC2(BigDecimal k, BigDecimal x, BigDecimal dt) {
        BigDecimal denominator = k.multiply(BigDecimal.valueOf(2).multiply(x).subtract(BigDecimal.ONE))
            .add(dt);
        return BigDecimal.ONE.subtract(denominator).divide(denominator, 
            8, RoundingMode.HALF_UP);
    }
}

5.3 预警功能设计

5.3.1 动态预警指标设计

预警规则配置模型

// 预警规则实体
public class OsmoticWarnRule {
    private Long id;
    private String ruleName;        // 规则名称
    private String ruleType;        // 规则类型1-渗压2-渗流3-位移
    private String deviceCode;      // 设备编码
    private BigDecimal threshold1;   // 一级阈值
    private BigDecimal threshold2;   // 二级阈值
    private BigDecimal threshold3;   // 三级阈值
    private String logicRelation;   // 逻辑关系AND/OR
    private Integer status;          // 状态0-禁用1-启用
    // ... 其他字段
}

预警条件判断算法

@Service
public class WarningRuleService {
    
    public WarningResult evaluateWarningRules(List<OsmoticWarnRule> rules, 
            Map<String, BigDecimal> sensorData) {
        WarningResult result = new WarningResult();
        List<WarningEvent> events = new ArrayList<>();
        
        for (OsmoticWarnRule rule : rules) {
            if (rule.getStatus() == 0) continue; // 跳过禁用规则
            
            BigDecimal currentValue = sensorData.get(rule.getDeviceCode());
            if (currentValue == null) continue;
            
            // 评估预警级别
            int level = evaluateWarningLevel(rule, currentValue);
            if (level > 0) {
                WarningEvent event = new WarningEvent();
                event.setRuleId(rule.getId());
                event.setRuleName(rule.getRuleName());
                event.setLevel(level);
                event.setCurrentValue(currentValue);
                event.setThreshold(getThresholdForLevel(rule, level));
                event.setTimestamp(LocalDateTime.now());
                
                events.add(event);
            }
        }
        
        result.setEvents(events);
        result.setHasWarning(!events.isEmpty());
        return result;
    }
    
    private int evaluateWarningLevel(OsmoticWarnRule rule, BigDecimal value) {
        if (rule.getThreshold3() != null && value.compareTo(rule.getThreshold3()) > 0) {
            return 3; // 三级预警
        } else if (rule.getThreshold2() != null && value.compareTo(rule.getThreshold2()) > 0) {
            return 2; // 二级预警
        } else if (rule.getThreshold1() != null && value.compareTo(rule.getThreshold1()) > 0) {
            return 1; // 一级预警
        }
        return 0; // 无预警
    }
}

5.3.2 预警发布系统设计

预警消息管理

@Service
public class MessageCenterService {
    
    public void publishWaterLevelWarning(List<StRsvrR> waterLevelData) {
        // 水位预警发布
        for (StRsvrR data : waterLevelData) {
            // 检查水位预警条件
            if (checkWaterLevelWarning(data)) {
                MessageCenter message = new MessageCenter();
                message.setTitle("水位预警");
                message.setContent(String.format("%s水库水位预警当前水位%.2fm,超过警戒水位", 
                    data.getStnm(), data.getRz()));
                message.setWarningLevel(calculateWarningLevel(data));
                message.setStationCode(data.getStcd());
                message.setCreateTime(LocalDateTime.now());
                message.setStatus(0); // 未读状态
                
                // 保存预警消息
                save(message);
                
                // 推送给相关用户
                pushToUsers(message);
            }
        }
    }
    
    public void publishOsmoticWarning(OsmoticWarnR warnData, String description) {
        // 渗压预警发布
        MessageCenter message = new MessageCenter();
        message.setTitle("渗压预警");
        message.setContent(String.format("%s渗压预警%s", 
            warnData.getDeviceName(), description));
        message.setWarningLevel(warnData.getWarningLevel());
        message.setDeviceCode(warnData.getDeviceCode());
        message.setCreateTime(LocalDateTime.now());
        message.setStatus(0);
        
        save(message);
        pushToUsers(message);
    }
}

用户推送机制

@Service
public class UserPushService {
    
    public void pushToUsers(MessageCenter message) {
        // 根据预警级别和用户角色推送消息
        List<User> targetUsers = getTargetUsers(message);
        
        for (User user : targetUsers) {
            // 创建用户消息记录
            UserMessage userMessage = new UserMessage();
            userMessage.setUserId(user.getId());
            userMessage.setMessageId(message.getId());
            userMessage.setReadStatus(0); // 未读状态
            userMessage.setPushTime(LocalDateTime.now());
            
            userMessageRepository.save(userMessage);
            
            // 实时推送WebSocket或其他推送机制
            if (user.isOnline()) {
                pushRealTimeNotification(user, message);
            }
        }
    }
    
    private List<User> getTargetUsers(MessageCenter message) {
        // 根据预警级别确定目标用户
        switch (message.getWarningLevel()) {
            case 3: // 三级预警(最高级别)
                return userRepository.findByRoleIn(Arrays.asList("ADMIN", "COUNTY_MANAGER"));
            case 2: // 二级预警
                return userRepository.findByRole("COUNTY_MANAGER");
            case 1: // 一级预警
                return userRepository.findByRoleIn(Arrays.asList("COUNTY_MANAGER", "FIELD_STAFF"));
            default:
                return Collections.emptyList();
        }
    }
}

5.3.3 预警统计分析

预警统计服务

@Service
public class WarningStatisticsService {
    
    public WarningStatistics getMonthlyStatistics(int year, int month) {
        // 月度预警统计
        WarningStatistics stats = new WarningStatistics();
        
        // 查询当月预警数据
        List<MessageCenter> warnings = messageCenterRepository
            .findByYearAndMonth(year, month);
        
        // 按类型统计
        stats.setWaterLevelCount(warnings.stream()
            .filter(w -> "水位预警".equals(w.getTitle()))
            .count());
        
        stats.setOsmoticCount(warnings.stream()
            .filter(w -> "渗压预警".equals(w.getTitle()))
            .count());
        
        // 按级别统计
        stats.setLevel1Count(warnings.stream()
            .filter(w -> w.getWarningLevel() == 1)
            .count());
        
        stats.setLevel2Count(warnings.stream()
            .filter(w -> w.getWarningLevel() == 2)
            .count());
        
        stats.setLevel3Count(warnings.stream()
            .filter(w -> w.getWarningLevel() == 3)
            .count());
        
        return stats;
    }
    
    public List<WarningTrend> getWarningTrend(int days) {
        // 预警趋势分析
        List<WarningTrend> trends = new ArrayList<>();
        
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(days);
        
        for (LocalDate date = startDate; date.isBefore(endDate); date = date.plusDays(1)) {
            WarningTrend trend = new WarningTrend();
            trend.setDate(date);
            trend.setCount(messageCenterRepository.countByDate(date));
            trends.add(trend);
        }
        
        return trends;
    }
}

5.4 县级用户功能设计

5.4.1 考核管理系统

考核任务工作流程

@Service
public class AssessTaskService {
    
    public AssessTask createTask(AssessTaskDTO dto) {
        // 创建考核任务
        AssessTask task = new AssessTask();
        BeanUtils.copyProperties(dto, task);
        task.setStatus(0); // 未启动状态
        task.setCreateTime(LocalDateTime.now());
        
        // 分配考核对象
        List<AssessObject> objects = assessObjectRepository.findByRegion(dto.getRegion());
        task.setAssessObjects(objects);
        
        // 设置考核指标
        List<AssessIndicator> indicators = assessIndicatorRepository.findByTaskType(dto.getTaskType());
        task.setIndicators(indicators);
        
        return assessTaskRepository.save(task);
    }
    
    @Transactional
    public String startTask(Long taskId) {
        // 启动考核任务
        AssessTask task = assessTaskRepository.findById(taskId)
            .orElseThrow(() -> new RuntimeException("任务不存在"));
        
        if (task.getStatus() != 0) {
            throw new RuntimeException("任务状态不允许启动");
        }
        
        task.setStatus(1); // 进行中状态
        task.setStartTime(LocalDateTime.now());
        
        // 通知考核对象
        notifyAssessObjects(task);
        
        assessTaskRepository.save(task);
        return "任务启动成功";
    }
    
    public List<AssessTask> getPendingTasks(Long userId) {
        // 获取用户待办任务
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        return assessTaskRepository.findByAssessorAndStatus(user, 1);
    }
    
    public List<AssessResultVo> getResult(Long taskId) {
        // 获取考核结果
        AssessTask task = assessTaskRepository.findById(taskId)
            .orElseThrow(() -> new RuntimeException("任务不存在"));
        
        List<AssessResult> results = assessResultRepository.findByTaskId(taskId);
        
        return results.stream().map(result -> {
            AssessResultVo vo = new AssessResultVo();
            vo.setObjectName(result.getObjectName());
            vo.setIndicatorName(result.getIndicatorName());
            vo.setScore(result.getScore());
            vo.setComment(result.getComment());
            return vo;
        }).collect(Collectors.toList());
    }
}

考核对象管理

@Service
public class AssessObjectService {
    
    public List<AssessObject> getObjectsByRegion(String region) {
        // 按区域获取考核对象
        return assessObjectRepository.findByRegion(region);
    }
    
    public List<AssessObject> getObjectsByType(String objectType) {
        // 按类型获取考核对象
        return assessObjectRepository.findByObjectType(objectType);
    }
    
    public void assignToTask(Long taskId, List<Long> objectIds) {
        // 分配考核对象到任务
        AssessTask task = assessTaskRepository.findById(taskId)
            .orElseThrow(() -> new RuntimeException("任务不存在"));
        
        List<AssessObject> objects = assessObjectRepository.findByIdIn(objectIds);
        task.setAssessObjects(objects);
        
        assessTaskRepository.save(task);
    }
}

5.4.2 权限管理系统

基于角色的权限控制

@Service
public class PermissionService {
    
    public boolean hasPermission(Long userId, String permission) {
        // 检查用户权限
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        return user.getRoles().stream()
            .flatMap(role -> role.getPermissions().stream())
            .anyMatch(p -> p.getCode().equals(permission));
    }
    
    public List<String> getUserPermissions(Long userId) {
        // 获取用户权限列表
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        return user.getRoles().stream()
            .flatMap(role -> role.getPermissions().stream())
            .map(Permission::getCode)
            .distinct()
            .collect(Collectors.toList());
    }
}

5.5 系统改进功能

5.5.1 防治点管理

防治点树形结构管理

@Service
public class PrePlaceService {
    
    public List<PrePlaceTreeVo> getPlaceTree() {
        // 获取防治点树形结构
        List<PrePlace> places = prePlaceRepository.findAllByOrderByParentIdAsc();
        
        return buildTree(places, null);
    }
    
    private List<PrePlaceTreeVo> buildTree(List<PrePlace> places, Long parentId) {
        List<PrePlaceTreeVo> tree = new ArrayList<>();
        
        for (PrePlace place : places) {
            if ((parentId == null && place.getParentId() == null) ||
                (parentId != null && parentId.equals(place.getParentId()))) {
                
                PrePlaceTreeVo vo = new PrePlaceTreeVo();
                vo.setId(place.getId());
                vo.setName(place.getPlaceName());
                vo.setCode(place.getPlaceCode());
                vo.setType(place.getPlaceType());
                vo.setChildren(buildTree(places, place.getId()));
                
                tree.add(vo);
            }
        }
        
        return tree;
    }
    
    public List<PrePlaceDetail> getPlaceDetails(Long placeId) {
        // 获取防治点详细信息
        return prePlaceDetailRepository.findByPlaceId(placeId);
    }
}

5.5.2 维护管理功能

维护计划管理

@Service
public class MentenancePlanService {
    
    public MentenancePlan createAnnualPlan(MentenancePlanDTO dto) {
        // 创建年度维护计划
        MentenancePlan plan = new MentenancePlan();
        BeanUtils.copyProperties(dto, plan);
        plan.setStatus(0); // 未启动状态
        plan.setCreateTime(LocalDateTime.now());
        
        // 创建维护详情
        List<MentencePlanDetail> details = dto.getDetails().stream()
            .map(detailDto -> {
                MentenancePlanDetail detail = new MentenancePlanDetail();
                BeanUtils.copyProperties(detailDto, detail);
                detail.setPlan(plan);
                return detail;
            })
            .collect(Collectors.toList());
        
        plan.setDetails(details);
        
        return mentenancePlanRepository.save(plan);
    }
    
    public void updatePlanStatus(Long planId, Integer status) {
        // 更新计划状态
        MentenancePlan plan = mentenancePlanRepository.findById(planId)
            .orElseThrow(() -> new RuntimeException("计划不存在"));
        
        plan.setStatus(status);
        if (status == 1) {
            plan.setStartTime(LocalDateTime.now());
        } else if (status == 2) {
            plan.setEndTime(LocalDateTime.now());
        }
        
        mentenancePlanRepository.save(plan);
    }
}

这些功能设计完整地覆盖了黑石咀水库系统的核心业务需求,包括基础数据管理、算法模型建设、预警功能、县级用户管理和系统改进功能,为系统的开发和实施提供了详细的技术指导。