# 大屏 — 疫病风险统计 — 技术方案 > 依据:同目录 `大屏疫病风险功能需求.md`;数据源为《实验室检测技术方案》《疫情上报技术方案》《检疫站管理技术方案》《风险因子设置技术方案》既有表。本模块为**大屏只读看板**,无业务台账 CRUD;**气象数据不由本模块提供**。 --- ## 1. 技术架构 | 项 | 说明 | | --- | --- | | **后端** | RuoYi **v3.9.2**(**springboot2** 分支):JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid | | **数据库** | MySQL **5.7.39**,InnoDB,`utf8mb4` | | **前端** | 大屏独立页面;**切换年份**拉取看板主数据,疫情列表**分页**单独请求;气象由前端调公开接口 | | **代码包** | `com.ruoyi.web.modules.screen`(`EpidemicRiskScreenController` / `IEpidemicRiskScreenService` / `vo` / `support`) | **分层**:`Controller` → `IEpidemicRiskScreenService`(口径编排、聚合)→ 扩展 Mapper / 复用既有 Service 只读查询。 | 场景 | 行为 | | --- | --- | | 进入 / 切换 `statYear` | 调用 **§3.1**(检测汇总、疫情统计、检疫态势、风险因子等) | | 疫情列表翻页 | 仅调用 **§3.2** | | 数据权限 | 全县数据,**不按**部门/用户过滤 | | 汇总口径 | 与功能需求 **§2** 一致;**样本来源**按 **Y**;**实验室检测趋势**为滚动 12 月、缺月补 0;解除时效为按疫病类型**算术平均天数** | | 检疫点 | **实时**主数据快照(与统计年份无关) | | 性能 | 默认实时聚合;可选 **§2.3** 缓存表 | **依赖表(只读)** | 表 | 用途 | | --- | --- | | `biz_lab_detection` | 样本来源、年度/月度检测量与阳性、检出率 | | `biz_epidemic_report` | 风险等级、类型、途径、列表、地区去重、解除时效 | | `biz_quarantine_station` | 可用/停用检疫点数(`del_flag=0`) | | `biz_risk_factor_weight` | 五项权重(单行 `id=1`) | --- ## 2. 数据库设计 ### 2.1 本模块业务表 **无新增业务台账表。** DDL 以各业务模块 `sql/*.sql` 为准。 ### 2.2 查询口径(按统计年份 `Y`) #### 实验室检测 `biz_lab_detection` | 项 | 条件 / 说明 | | --- | --- | | 按年(样本来源) | `selectByTestYear(Y)`;`test_date` 在 **Y** 年内 | | 滚动 12 月(趋势区) | `selectByTestDateBetween(rangeStart, rangeEnd)`;锚点 = `HomeScreenSupport.currentYearMonth()`;窗口 `[anchor−11 月 1 日, rollingWindowEnd]` | | 样本来源汇总 | 基于 **Y** 年记录 `GROUP BY sample_source`,`SUM(test_quantity)` | | 趋势区合计 | 滚动窗口内 `SUM(test_quantity)`、`SUM(positive_count)` | | 按月趋势 | 按 `YEAR(test_date)`+`MONTH(test_date)` 聚合;`EpidemicRiskScreenSupport.buildLabDetection(rows, anchor)` 补全 **12** 槽位,含 `statYear`、`month` | **`sample_source`**:`1` 场地抽检 / `2` 疫情上报送检 / `3` 调运检疫 / `4` 日常检测。 #### 疫情上报 `biz_epidemic_report` | 统计用途 | SQL 条件要点 | | --- | --- | | 按上报日(饼图、列表、类型、途径等) | `report_date` 在 **Y** 年内 | | 防控中地区 | `report_date` 在 **Y** 年内 AND `release_date IS NULL` | | 已解除地区、解除时效 | `release_date IS NOT NULL` AND `release_date` 在 **Y** 年内 | | 未解除判定 | `release_date IS NULL` | | 地区去重 | 对 `affected_location_track` **DISTINCT** 计数(应用层亦可) | **枚举(入库值,展示名见功能需求 §2.6)** | 字段 | 值 | 含义 | | --- | --- | --- | | `risk_level` | 1 / 2 / 3 | 高危 / 中危 / 低危 | | `epidemic_type` | 1~4 | 病毒 / 细菌 / 寄生虫 / 其他 | | `transmission_route` | 1~4 | 调运 / 本地扩散 / 环境 / 其他未知 | **解除时效(平均天)**:对满足「已解除且解除日在 Y」的记录,`DATEDIFF(release_date, report_date)` 按 `epidemic_type` 分组后求 **AVG**(四类型固定返回,无记录时 `avgDays=null`)。 #### 检疫站 `biz_quarantine_station` | 项 | 条件 | | --- | --- | | 范围 | `del_flag = '0'` | | 可用检疫点 | `operate_status = 1`(正常) | | 停用检疫点 | `operate_status IN (2, 3)`(停业、注销) | > **不按** `statYear` 过滤;取当前库内快照。 #### 风险因子 `biz_risk_factor_weight` | 项 | 条件 | | --- | --- | | 读取 | `SELECT * FROM biz_risk_factor_weight WHERE id = 1` | | 无记录 | 返回 `hasRiskFactorConfig=false`,前端走空态 | ### 2.3 可选表 `biz_epidemic_risk_screen_cache`(性能优化) **非本期必建。** | 字段 | 类型 | 说明 | | --- | --- | --- | | `id` | `bigint(20)` | 主键 | | `stat_year` | `int(11)` | 统计年份 | | `payload_json` | `mediumtext` | **§3.1** 响应 JSON(不含分页列表) | | `expire_time` | `datetime` | 过期时间 | | `create_time` | `datetime` | 写入时间 | **索引**:`UNIQUE uk_stat_year (stat_year)`。TTL 建议 **1~5 分钟**。 ### 2.4 索引建议(既有表) | 表 | 建议 | | --- | --- | | `biz_lab_detection` | 沿用 `idx_test_date`、`idx_sample_source` | | `biz_epidemic_report` | 沿用 `idx_report_date`、`idx_release_date`、`idx_risk_level` | | `biz_quarantine_station` | 沿用 `idx_publish` 等价 `operate_status` 索引(见检疫站 DDL) | ### 2.5 Mapper 扩展(建议) | Mapper | 方法 | 说明 | | --- | --- | --- | | `BizLabDetectionMapper` | `selectByTestYear(int statYear)` | 当年全部检测行(聚合在 Service) | | `BizLabDetectionMapper` | `selectDistinctTestYears()` | 可选年份 | | `BizEpidemicReportMapper` | `selectByReportYear(int statYear)` | 上报日在 Y 年内 | | `BizEpidemicReportMapper` | `selectRelievedByReleaseYear(int statYear)` | 已解除且解除日在 Y | | `BizEpidemicReportMapper` | `selectActiveControlByReportYear(int statYear)` | 上报日在 Y 且未解除 | | `BizEpidemicReportMapper` | `selectDistinctReportYears()` | 可选年份 | | `BizQuarantineStationMapper` | `countByOperateStatus(int status)` | 按运营状态计数 | | `BizRiskFactorWeightMapper` | `selectConfig()` | 读 `id=1`(可复用既有查询) | --- ## 3. 接口设计 **统一响应**:`AjaxResult`(`code` / `msg` / `data`);疫情列表用 `TableDataInfo`(`rows` / `total`)。 **权限标识(示例)**:`bigScreen:epidemicRisk:query` **Base Path**:`/bigScreen/epidemicRisk` | # | 说明 | Method | URI | 权限 | | --- | --- | --- | --- | --- | | 3.1 | 看板主数据 | GET | `/bigScreen/epidemicRisk/dashboard` | `bigScreen:epidemicRisk:query` | | 3.2 | 疫情上报分页列表 | GET | `/bigScreen/epidemicRisk/reports` | 同上 | 前端:切换 `statYear` → **3.1** + **3.2**(`pageNum=1`);仅翻页 → **3.2**。 --- ### 3.1 看板主数据 #### Query | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `statYear` | string | Y | 四位年份;非法 → 业务异常(复用 `AchievementReportValidation.parseStatYear` 或同等校验) | | `forceRefresh` | boolean | N | 默认 `false`;`true` 跳过 **§2.3** 缓存 | #### 响应 `data` 结构(节选) | 字段 | 说明 | | --- | --- | | `statYear` | 回显 | | `availableYears` | `int[]`,检测年与上报年并集 + 当前年,降序 | | `hasLabData` | 该年是否存在 ≥1 条检测记录 | | `hasEpidemicData` | 该年按上报日是否存在 ≥1 条疫情上报 | | `labDetection` | 见 **§3.1.1** | | `sampleSourceStats` | 见 **§3.1.2** | | `riskLevelStats` | 风险等级饼图 **§3.1.3** | | `epidemicSituation` | 检疫点 + 地区 **§3.1.4** | | `epidemicTypeStats` | 疫病类型占比 | | `transmissionRouteStats` | 传播途径数量与占比 | | `relieveDurationByType` | 按类型平均解除天数 **§3.1.5** | | `riskFactorWeights` | 五项权重 **§3.1.6** | #### 3.1.1 `labDetection` | 字段 | 说明 | | --- | --- | | `testQuantityTotal` | 滚动 12 月窗口内检测量合计 | | `positiveCountTotal` | 滚动 12 月窗口内阳性合计 | | `positiveRate` | 检出率 0~1;`testQuantityTotal=0` 时为 `null` 或 `0`(与产品约定) | | `monthly` | 长度 **12**;**滚动最近 12 月**;每项含 `statYear`、`month`、`testQuantity`、`positiveCount`;缺月为 **0** | #### 3.1.2 `sampleSourceStats[]` | 字段 | 说明 | | --- | --- | | `sampleSource` | 1~4 | | `sampleSourceName` | 中文名 | | `testQuantity` | 份 | | `ratio` | 占当年检测量合计,0~1 | 固定返回 **4** 项(无数据时 `testQuantity=0`、`ratio=0`)。 #### 3.1.3 `riskLevelStats[]` | 字段 | 说明 | | --- | --- | | `riskLevel` | 1 / 2 / 3 | | `riskLevelName` | 高危 / 中危 / 低危 | | `count` | 条数 | | `ratio` | 占当年按上报日纳入总数 | 固定 **3** 项。 #### 3.1.4 `epidemicSituation` | 字段 | 说明 | | --- | --- | | `availableQuarantinePointCount` | 正常运营检疫站数 | | `disabledQuarantinePointCount` | 停业+注销检疫站数 | | `activeControlAreaCount` | 防控中地区数(涉疫点位去重) | | `releasedAreaCount` | 已解除地区数(涉疫点位去重) | #### 3.1.5 `relieveDurationByType[]` | 字段 | 说明 | | --- | --- | | `epidemicType` | 1~4 | | `epidemicTypeName` | 中文名 | | `avgRelieveDays` | 平均解除天数;该类型无已解除记录时为 `null` | | `recordCount` | 参与平均的条数(可选,便于前端展示) | #### 3.1.6 `riskFactorWeights` | 字段 | 说明 | | --- | --- | | `hasRiskFactorConfig` | 是否存在 `id=1` 配置 | | `items` | 固定 5 项:`factorCode`、`factorName`、`weight`(decimal) | `factorCode` 建议:`breedingDensity`、`trafficMobility`、`quarantineIntensity`、`meteorologicalSuitability`、`pastDiseaseLevel`。 --- ### 3.2 疫情上报分页列表 #### Query | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `statYear` | string | Y | 同 **3.1** | | `pageNum` | int | N | 默认 `1` | | `pageSize` | int | N | 默认 `8` | #### 响应 `TableDataInfo`:`rows` 为 **§3.2.1**,`total` 为当年按上报日纳入的总条数。 **不提供** `GET /{id}` 大屏详情接口。 #### 3.2.1 `rows[]` | 字段 | 说明 | | --- | --- | | `id` | 主键 | | `reportDate` | `yyyy-MM-dd` | | `transmissionRoute` / `transmissionRouteName` | 编码 + 展示名 | | `epidemicType` / `epidemicTypeName` | 编码 + 展示名 | | `epidemicName` | 疫病名称 | | `riskLevel` / `riskLevelName` | 编码 + 展示名 | | `affectedLocationTrack` | 涉疫点位/轨迹 | | `relieveStatus` | `0` 未解除 / `1` 已解除 | | `releaseDate` | 已解除时有值 | 默认排序:`report_date DESC, create_time DESC, id DESC`。 --- ### 3.3 服务端逻辑(摘要) ``` 1. year = parseStatYear(statYear) 2. labRows = selectByTestYear(year) 3. reportRows = selectByReportYear(year) 4. relievedRows = selectRelievedByReleaseYear(year) 5. activeRows = selectActiveControlByReportYear(year) 6. 组装 labDetection、sampleSourceStats(固定4类) 7. 组装 riskLevelStats(固定3类)、epidemicTypeStats、transmissionRouteStats 8. epidemicSituation = 检疫站 count + 地区 distinct(activeRows/relievedRows) 9. relieveDurationByType = AVG(DATEDIFF) GROUP BY epidemic_type(固定4类) 10. riskFactorWeights = selectConfig id=1 11. availableYears = union(distinct test years, distinct report years, current year) 12. return AjaxResult.success(vo) ``` **枚举展示名**:`EpidemicRiskScreenSupport` 集中维护 code→name,与功能需求 §2.6 一致。 --- ## 4. 菜单与权限(示例) | 类型 | 名称 | 权限标识 | | --- | --- | --- | | 菜单 | 大屏疫病风险 | `bigScreen:epidemicRisk:query` | SQL 示例:`sql/big_screen_epidemic_risk_perm.sql`(挂载「大屏」父菜单下)。 --- ## 5. 交付清单 - [ ] `EpidemicRiskScreenController` + `IEpidemicRiskScreenService` + VO + `EpidemicRiskScreenSupport` - [ ] `BizLabDetectionMapper` / `BizEpidemicReportMapper` 大屏统计 SQL - [ ] 单元测试:缺月补 0、检出率、占比、地区去重、平均解除时效、无配置权重 - [ ] 接口测试:`/dashboard`、`/reports` - [ ] 菜单权限 SQL - [ ] 依赖四张业务表 DDL 已执行 --- ## 6. 修订记录 | 版本 | 日期 | 说明 | | --- | --- | --- | | 1.0 | 2026-05-25 | 初稿:无新表;双接口;对齐功能需求 v1.1(解除时效为平均天数);气象不在本模块 |