fastbee/docs/fastbee-device-report-engine.md
2026-09-22 21:30:47 +08:00

21 KiB
Raw Blame History

FastBee IoT 设备监测报告引擎开发 Skill

领域背景:公司主营业务为桥梁、建筑、边坡、隧道等结构老化与安全监测,核心监测对象为裂缝、深部位移、轴力/应力、沉降、倾角、应变、振动等工程物理量。

本 Skill 目标:基于已落库的 IoT 物模型监测数据,为单个监测设备按「设备 + 时间范围」生成专业分析报告(Word .docx),支持历史报表下载,保留期 1 个月。

前端入口(2 处):① 大屏分析模式;② 数据中心分析页。两处均通过「选设备 + 选时间」即可生成并导出分析报告;另有历史报表列表可下载。

存储决策:已确认未购买云 OSS 服务 → 统一使用自建 MinIO(S3 协议兼容,复用现有 fastbee-oss 插件,不改上传链路)。

第一阶段范围:单设备报告。不在范围:项目综合报告、多设备联合分析、AI 自动工程安全判定、在线 Word 模板编辑器。


1. 现状盘点(已代码确认,先读后写)

1.1 存储结论:OSS 未购买 → MinIO

检查项 结论
oss_config 初始化数据(oss.sql / sql/yack-init.sql) 仅有 aliyun/qiniu 两条记录,access_key/secret_key 均为占位符 XXXXXXXXXXXXXXX,无真实云 OSS 配置
fastbee-plugs/fastbee-oss 基于 aws-java-sdk-s3(S3 协议);OssClient 显式兼容 MinIO:endpoint 非云服务商关键字时自动启用 path-style,getUrl() 有 minio 单独分支
结论 未购买 OSS → 使用自建 MinIO。复用 OssFactory/OssClient,禁止新写 MinIO/S3 Service。只需:PlatformType 增加 MINIO、oss_config 插入 minio 默认记录、部署 MinIO 并配置 30 天生命周期规则

1.2 可复用能力

能力 位置 复用方式
设备/产品/物模型实体 Device.java / Product.java / ThingsModel.java 直接复用,禁止新建重复 DTO
时序数据查询 DeviceLogMapper.listHistory(MySQL)/ TDDeviceLogMapper(TDengine) 报告模块通过 Provider 委托,禁止自写 SQL
数据中心分析能力 DataCenterController(/data/center/deviceStats、deviceDataQuality、deviceHistogram) 报告统计/质量可复用其 Service 层逻辑
文件上传 OssFactory.instance(redis).upload(byte[], path, contentType) → UploadResult{url, filename} 上传到 MinIO
文件读取/删除 OssClient.getObjectContent(path) / delete(path) 下载代理、过期清理兜底
Word/POI poi-ooxml 4.1.2(已有) 新增 poi-tl 做模板渲染
Excel easyexcel 3.3.1(已有) 如需导出原始数据复用
MQ fastbee-mq(RocketMQ) 未来异步报告任务复用

1.3 关键缺失(本 Skill 补齐)

  1. fastbee-report 模块:报告引擎、Analyzer、report_record 表(均不存在)。
  2. 设备监测分类路由:DeviceType 是连接拓扑(直连/网关/摄像头),iot_category 是租户商务分类树,均不能作为分析路由键 → 需 iot_product.monitor_category_code + MonitorCategory 枚举。
  3. 报告周期/时间窗口:ReportPeriod 枚举 + ReportPeriodResolver。
  4. 结构化报告阈值:告警阈值藏在 LiteFlow iot_scene 脚本里,报告不可直接读 → 新增 iot_things_threshold。
  5. Java 端图表(JFreeChart)与 Word 模板引擎(poi-tl)。
  6. MinIO 默认存储配置。
  7. 前端两处「生成并导出分析报告」按钮 + 历史报表页(列表/下载/过期)。

1.4 前端现状

入口 页面 现状
大屏分析模式 yack-web/src/views/bigScreen/home.vue(activeMode === 'analysis') 已有「设备选择 + 时间范围(预设 5m~7d / 自定义)+ 查询数据和曲线」,无报表按钮
数据中心 yack-web/src/views/dataCenter/analysis.vue 已有「设备 + 时间范围」查询(统计/数据质量/直方图/趋势),无报表按钮
历史报表 无 需新增列表 + 下载

2. 整体逻辑链路

前端(大屏分析模式 / 数据中心):选设备 + 时间范围
        ↓ POST /iot/report/generate {deviceId, startTime, endTime}
ReportRequest
        ↓
ReportPeriodResolver → TimeWindow(周期预设或自定义)
MonitorCategoryResolver → MonitorCategory(读 iot_product.monitor_category_code)
        ↓
ReportContextBuilder → ReportContext(设备/产品/物模型/时序数据/阈值一次性装配)
        ↓
ReportAnalyzerFactory.get(category) → 专项 Analyzer(V1:CrackMeterAnalyzer)
        ↓
AnalysisResult(统计/趋势/质量/预警/结论/图表数据)
        ↓
ReportModel → WordRenderer(poi-tl {{}} + JFreeChart PNG)→ byte[]
        ↓
OssFactory → MinIO 上传 → fileUrl
        ↓
report_record 落库(status=SUCCESS,expire_time = create_time + 30 天)
        ↓
返回 reportNo / fileUrl → 前端直接下载,或进历史报表

历史报表:

GET /iot/report/list                → 分页返回未过期记录
GET /iot/report/download/{reportNo} → 校验 expire_time → OssClient 流式下载
过期双保险:MinIO 生命周期 30 天删除兜底 + 下载接口返回“报告已过期”

3. 后端实现方案

3.1 新增模块 fastbee-report

依赖方向(禁止反向依赖、禁止循环依赖):

fastbee-admin / fastbee-open-api(REST 入口)
        ↓
fastbee-report(报告引擎核心)
        ↓
fastbee-iot-service + fastbee-iot-data + fastbee-oss + fastbee-common
        ↓
MySQL / TDengine / MinIO

核心目录:

fastbee-report/
├── api/         ReportEngine, ReportRequest, ReportResult
├── core/        DefaultReportEngine, ReportContext, ReportContextBuilder, ReportAssembler
├── category/    MonitorCategoryResolver(+Default)
├── period/      ReportPeriodResolver(+Default), TimeWindow
├── analyzer/    ReportAnalyzer, ReportAnalyzerFactory(+Default), crack/CrackMeterAnalyzer
├── analysis/    StatisticsCalculator, TrendAnalyzer, RateCalculator, QualityAnalyzer, WarningAnalyzer
├── threshold/   ThingsThresholdProvider(+Db 实现), ThingsThreshold
├── data/        ReportDataProvider, MetricData
├── model/       ReportModel, AnalysisResult, Statistics, TrendAnalysis, QualityAnalysis, WarningAnalysis, ChartData
├── chart/       ChartGenerator(JFreeChart 生成 PNG)
├── renderer/    ReportRenderer, WordRenderer(poi-tl), WordTemplateResolver
├── record/      ReportRecord, ReportRecordMapper, ReportRecordService
└── exception/   ReportException

3.2 核心流程(DefaultReportEngine)

1. 参数校验:deviceId 必填;startTime/endTime 与 period 二选一(都传时以自定义为准);endTime > startTime
2. 时间窗口:period != CUSTOM 时按自然日历计算
     日报=当日 0-24;周报=周一~周日;半月报=1~15 / 16~月末;月报=1~月末(时区 GMT+8)
3. 分类路由:MonitorCategoryResolver.resolveByDeviceId → MonitorCategory
4. 构建上下文:设备/产品/物模型(isMonitor=1)/时序数据/阈值 一次性装入 ReportContext
5. analyzerFactory.get(category).analyze(context, request) → AnalysisResult
6. reportAssembler.assemble(...) → ReportModel
7. reportRenderer.render(...) → byte[] → MinIO 上传 → ReportResult{reportNo, fileUrl, expireTime}
8. reportRecordService 落库(SUCCESS / FAILED + expire_time)

禁止:ReportEngine 直接操作 Mapper;Analyzer 自己 @Autowired 业务 Service 查询;WordRenderer 查库。

3.3 设备监测分类(MonitorCategory)

  • 现有 DeviceType(连接拓扑)与 iot_category(商务分类树)均不能作为分析路由键。
  • iot_product 新增 monitor_category_code VARCHAR(64)(可空),值如 CRACK_METER、DEEP_DISPLACEMENT、AXIAL_FORCE、STATIC_LEVEL、VIBRATING_WIRE;存量产品按产品名 SQL 回填。
  • MonitorCategory 枚举放 fastbee-common;解析不到返回 UNKNOWN 并报「未配置监测分类」,不启发式猜测。
  • 新增设备类型 = 新增一个 Analyzer(实现 supports(category)),不改 ReportEngine、不写 if(category==xxx) 巨型判断。

3.4 时间范围(ReportPeriod)

  • 枚举:DAY / WEEK / HALF_MONTH / MONTH / CUSTOM,放 fastbee-common。
  • 前端两入口当前均传自定义时间范围(startTime/endTime);周期预设(日/周/半月/月)留给后台与后续使用。
  • ReportPeriodResolver 计算自然日历窗口;必须单测边界:周一/月末/闰年二月/半月报 15 日分界。

3.5 阈值(WarningAnalyzer)

  • 现状:告警阈值藏在 LiteFlow iot_scene 脚本里,报告引擎直接解析成本高、易错。
  • V1:新增 iot_things_threshold 表(字段:product_id、device_id、monitor_category_code、metric_identifier、warning_value、alarm_value、control_value、unit)。
  • 查询优先级:device_id > product_id > 全局默认(product_id=0)。Analyzer 只读结构化阈值,禁止硬编码阈值。

3.6 分析能力(通用 + 专项)

  • 通用:统计(当前/初始/极值/均值/中位/变化量/累计变化)、趋势(线性回归 UP/DOWN/STABLE/FLUCTUATION + 斜率 + R²)、数据质量(缺失/重复/越界/完整率)、预警(NORMAL/WARNING/ALARM)。
  • 专项:V1 只实现裂缝计 CrackMeterAnalyzer(当前/初始宽度、变化量、速率、趋势、预警、时程图),跑通后扩展深部位移/轴力/静力水准/振弦。
  • 图表:后端 JFreeChart 生成 PNG 嵌入 Word;禁止前端生成图回传后端。
  • 结论:基于结构化分析结果用规则+模板生成文字,不用 AI 直接判断结构安全。

3.7 Word 渲染

  • 新增依赖:poi-tl 1.10.4(兼容 POI 4.1.2)、jfreechart 1.5.4;禁止再引入 docx4j。
  • 模板:DEVICE_CRACK_METER_V2.docx 等,按 template_code(DEVICE_${CATEGORY}_V2)从 classpath 的 templates/ 目录加载(DefaultWordTemplateResolver)。模板与渲染逻辑强耦合,不入库,随代码版本发布。
  • 变量:{{report.no}}、{{report.periodDesc}}、{{device.name}}、{{device.serialNumber}}、{{analysis.statistics.max}}、{{analysis.statistics.delta}}、{{analysis.trend.description}}、{{analysis.warning.status}}、循环表格 {{conclusions}}、图片 {{charts.crackTrend}} 等;模板不直接绑定数据库字段。

4. 存储方案:MinIO(关键决策)

4.1 结论与理由

  • 仓库内 oss_config 无真实云 OSS 密钥(占位符),确认未购买 OSS 服务。
  • MinIO 自建、S3 协议,现有 OssClient 已兼容:endpoint 不含 aliyun/qcloud/qiniu/obs 关键字时自动启用 path-style;getUrl() 对 minio 单独处理。
  • 因此不改上传代码,只做:部署 MinIO + oss_config 配置 + PlatformType 增加枚举 + 过期策略。

4.2 部署(Docker Compose 单节点示例)

services:
  minio:
    image: minio/minio:latest
    command: server /data --console-address ":9001"
    ports:
      - "9000:9000"   # S3 API
      - "9001:9001"   # 控制台
    environment:
      MINIO_ROOT_USER: fastbee-minio
      MINIO_ROOT_PASSWORD: <强密码>
    volumes:
      - minio-data:/data

启动后:创建 bucket fastbee,并在控制台生成 AccessKey/SecretKey。

4.3 系统配置(oss_config 插入默认记录)

-- 先停用云 OSS 配置(存量占位符)
UPDATE `oss_config` SET `status` = '1' WHERE `config_key` IN ('aliyun', 'qiniu');

-- 插入 MinIO 默认配置(endpoint 为云服务器地址,供后端 S3 SDK 连接)
INSERT IGNORE INTO `oss_config`
(tenant_id, tenant_name, config_key, access_key, secret_key, bucket_name, prefix,
 endpoint, domain, is_https, region, access_policy, status, del_flag, create_by, create_time, update_by, update_time, remark)
VALUES
(1, 'admin', 'minio', 'supermeminio', 'minio20260909', 'fastbee', 'report',
 'http://47.1.28.77:9000', '', 'N', '', '0', '0', '0', 'admin', NOW(), 'admin', NOW(), 'MinIO默认存储');

要点:

  • status='0' 设为默认,启动时 OssApplicationRunner 自动装载进 Redis(sys_oss:default_config)。
  • endpoint 为后端连接 MinIO 的 S3 API 地址,需确保端口 9000 在安全组/防火墙放行;若后端与 MinIO 同机部署,可改为 http://127.0.0.1:9000。
  • domain 为空时,getUrl() 返回 http://<endpoint>/<bucketName>;若配置了 CDN 或公网域名,可填入以生成更友好的 URL。
  • PlatformType 增加 MINIO(5, "MinIO")(仅用于管理页展示;实际路由走 config_key)。
  • access_policy=0(私有),报告下载统一走后端代理接口(GET /iot/report/download/{reportNo}),可校验权限和过期状态。
  • bucket_name='fastbee':需在 MinIO 中提前创建此 bucket。
  • endpoint 需根据实际 MinIO 部署地址修改(如 http://192.168.1.100:9000 或生产域名)。
  • bucket_name='fastbee':需在 MinIO 中提前创建此 bucket。

4.4 报告文件路径

/report/yyyy/MM/dd/device/{deviceId}/{reportNo}.docx
例:/report/2026/08/16/device/10001/REPORT-202608160001.docx

禁止把 Word 永久存服务器本地。

4.5 历史报表过期 1 个月(双保险)

  1. 业务层:report_record.expire_time = create_time + 30 天;列表只返回未过期记录;下载接口校验过期并提示「报告已过期」。
  2. 存储层兜底:MinIO 生命周期规则删除 report/ 前缀下 30 天前的对象:
mc ilm rule add local/fastbee --prefix report/ --expire-days 30
  1. 下载实现(推荐后端代理流式下载,可校验权限 + 过期):
// 上传(复用现有插件)
UploadResult r = OssFactory.instance(redis)
        .upload(docBytes, path, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");

// 下载:按 reportNo 查 report_record → 校验 expire_time → getObjectContent(path) 流式输出

5. 前端实现方案

5.1 入口一:大屏分析模式(bigScreen/home.vue)

  • 在「分析条件」卡片“查询数据和曲线”旁新增按钮 「生成并导出分析报告」。
  • 参数直接取已有 analysisQuery.deviceId + analysisQuery.timeRange([startTime, endTime])。
  • 交互:点击 → POST /iot/report/generate(loading 防重复)→ 成功拿 reportNo/fileUrl 直接触发下载,并提示可在历史报表查看。
  • 未选设备或时间时按钮禁用。
// 参考实现(新增到 home.vue methods)
async handleGenerateReport() {
  const [startTime, endTime] = this.analysisQuery.timeRange || [];
  if (!this.analysisQuery.deviceId || !startTime || !endTime) {
    this.$message.warning('请先选择设备和时间范围');
    return;
  }
  const res = await generateDeviceReport({
    deviceId: this.analysisQuery.deviceId,
    startTime,
    endTime,
    templateCode: 'DEVICE_CRACK_METER_V1',
    format: 'WORD',
  });
  // res.data.fileUrl → window.open 或 a[download] 下载
}

5.2 入口二:数据中心(dataCenter/analysis.vue)

  • 在筛选栏“查询/重置”旁新增 「生成并导出分析报告」。
  • 参数取已有 queryParams.deviceId + queryParams.dayDaterange。
  • 交互与 5.1 一致,复用同一 API 封装。

5.3 历史报表(新页面/面板)

  • 入口建议:数据中心新增 tab「历史报表」(或大屏个人中心),接口权限 iot:report:list。
  • 列表字段:报告编号、设备名称、监测分类、周期、时间范围、生成时间、过期时间、状态、操作(下载)。
  • 只展示未过期记录;已过期记录不展示(或置灰提示「已过期」)。
  • 下载:GET /iot/report/download/{reportNo},走浏览器下载。

6. API 设计

POST /iot/report/generate            生成报告(同步,V1)
GET  /iot/report/list                历史报表(分页,仅未过期)
GET  /iot/report/download/{reportNo} 下载(校验过期,代理下载)

生成请求(前端两入口的通用格式):

POST /iot/report/generate
{
  "deviceId": 10001,
  "startTime": "2026-08-01 00:00:00",
  "endTime": "2026-08-08 23:59:59",
  "templateCode": "DEVICE_CRACK_METER_V1",
  "format": "WORD"
}

可选周期预设(后台/后续使用):

{
  "deviceId": 10001,
  "period": "WEEK",
  "anchorDate": "2026-08-09",
  "templateCode": "DEVICE_CRACK_METER_V1"
}

响应:

{
  "code": 200,
  "data": {
    "reportNo": "REPORT-202608160001",
    "status": "SUCCESS",
    "fileName": "304259363251-周报-监测分析报告.docx",
    "fileUrl": "http://minio-host:9000/fastbee/report/2026/08/16/device/10001/REPORT-202608160001.docx",
    "expireTime": "2026-09-15 23:59:59"
  }
}

权限:

@PreAuthorize("@ss.hasPermi('iot:report:generate')")                        // 生成(写)
@PreAuthorize("@ss.hasAnyPermi('iot:report:list,iot:device:list')")        // 列表/下载(读,跨页面复用)

7. 数据库改动

对象 说明
iot_product 加列 monitor_category_code VARCHAR(64) 可空;存量按产品名回填(如 UPDATE iot_product SET monitor_category_code='CRACK_METER' WHERE product_name LIKE '%裂缝%')
iot_things_threshold 物模型阈值表(product/device 级:预警/报警/控制值 + 速率双控)
report_record 报告记录表(含 expire_time)
oss_config 插入 minio 默认配置记录(见 4.3)

report_record 核心字段:

CREATE TABLE report_record (
  id          BIGINT PRIMARY KEY AUTO_INCREMENT,
  report_no   VARCHAR(64) NOT NULL COMMENT 'REPORT-yyyyMMddHHmmss-xxxx',
  device_id   BIGINT NOT NULL,
  monitor_category_code VARCHAR(64),
  period      VARCHAR(32) COMMENT 'DAY/WEEK/HALF_MONTH/MONTH/CUSTOM',
  start_time  DATETIME,
  end_time    DATETIME,
  status      VARCHAR(16) COMMENT 'CREATING/SUCCESS/FAILED',
  file_url    VARCHAR(512),
  expire_time DATETIME COMMENT '过期时间 = create_time + 30 天',
  error_message VARCHAR(1024),
  tenant_id   BIGINT,
  create_by   VARCHAR(64),
  create_time DATETIME,
  KEY idx_device (device_id, create_time),
  KEY idx_expire (expire_time)
) COMMENT '报告生成记录';

8. 开发顺序

  1. 基础设施:根 pom 声明 poi-tl/jfreechart 版本;建 3 张新表 + iot_product 加列;MonitorCategory/ReportPeriod 枚举;MinIO 部署 + oss_config 默认记录 + PlatformType.MINIO。
  2. fastbee-report 骨架:模块注册进根 pom;ReportRequest/ReportEngine/ReportContext。
  3. 分类与周期:MonitorCategoryResolver、ReportPeriodResolver + 边界单测。
  4. Analyzer 框架 + 裂缝计:先只实现 CrackMeterAnalyzer。
  5. 通用分析:StatisticsCalculator/TrendAnalyzer/RateCalculator/QualityAnalyzer/WarningAnalyzer。
  6. Provider:ReportDataProvider(委托 DeviceLogMapper)、ThingsThresholdProvider。
  7. 渲染:ChartGenerator(JFreeChart)+ WordRenderer(poi-tl)+ 模板 DEVICE_CRACK_METER_V1.docx。
  8. 落库与下载:report_record + expire_time;MinIO 生命周期规则;下载接口(校验过期)。
  9. 前端:大屏分析模式 + 数据中心加「生成并导出分析报告」;历史报表页 + 下载。
  10. 闭环验证:真实设备 + 时间范围 → 生成 → 下载 → 列表可见 → 过期处理验证。

9. Definition of Done

[ ] MinIO 部署完成,oss_config 默认 minio 记录生效(OssFactory 可上传/下载)
[ ] fastbee-report 模块创建完成,Maven 无循环依赖
[ ] iot_product.monitor_category_code + 3 张新表建好
[ ] ReportPeriodResolver 边界单测通过
[ ] CrackMeterAnalyzer 跑通(设备 + 时间 → AnalysisResult)
[ ] WordRenderer(poi-tl) + ChartGenerator(JFreeChart) 生成 DOCX
[ ] 生成接口返回 reportNo / fileUrl / expireTime
[ ] report_record 落库,expire_time = +30 天
[ ] 列表接口只返回未过期记录
[ ] 下载接口可下载;过期返回明确提示
[ ] 大屏分析模式与数据中心均可「生成并导出分析报告」
[ ] 历史报表页面可查看/下载
[ ] 设备 304259363251 完整闭环验证通过

10. 不允许的设计

❌ 新写 MinIO/S3 Service(必须复用 OssFactory/OssClient)
❌ 报告文件永久存服务器本地
❌ ReportEngine / WordRenderer 直接查库
❌ Analyzer 硬编码阈值 / 所有设备写一个 Analyzer / if(category==xxx)
❌ 复用 DeviceType 或 iot_category 作为监测分类路由键
❌ 前端生成图表回传后端
❌ 报告模块反向依赖 fastbee-iot-service 之外、造成循环依赖
❌ 引入 docx4j、新 OSS SDK 等重复依赖

11. 第一阶段范围外(预留)

项目综合报告、多设备联合分析、AI 自动工程安全判定、在线 Word 模板编辑器、异步生成(后续可走 fastbee-mq RocketMQ)。