# 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. 整体逻辑链路 ```text 前端(大屏分析模式 / 数据中心):选设备 + 时间范围 ↓ 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 → 前端直接下载,或进历史报表 ``` 历史报表: ```text GET /iot/report/list → 分页返回未过期记录 GET /iot/report/download/{reportNo} → 校验 expire_time → OssClient 流式下载 过期双保险:MinIO 生命周期 30 天删除兜底 + 下载接口返回“报告已过期” ``` --- # 3. 后端实现方案 ## 3.1 新增模块 fastbee-report 依赖方向(禁止反向依赖、禁止循环依赖): ```text fastbee-admin / fastbee-open-api(REST 入口) ↓ fastbee-report(报告引擎核心) ↓ fastbee-iot-service + fastbee-iot-data + fastbee-oss + fastbee-common ↓ MySQL / TDengine / MinIO ``` 核心目录: ```text 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) ```text 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}}` 等;模板不直接绑定数据库字段。 ## 3.8 主监测指标(模板里的"监测指标") `{{device.metricName}}` 的值来自 `AnalysisResult.primaryIdentifier` → `Statistics.modelName` (即 `iot_things_model.model_name` 的中文名),由 `PrimaryMetricResolver.resolve` 判定, 优先级从高到低: 1. **用户显式指定** —— `iot_things_threshold.is_primary` 为真的物模型直接当选, 不受辅助量黑名单与关键词限制。级别口径与阈值数值**同一套**(逐标识符 `device > product`): 设备级配了该物模型就以设备行为准(设备行没勾、产品行勾了也不作数),设备没配才继承产品行的勾选。 多个标记项同时有数据时,取物模型列表顺序最靠前的(与关键词命中同口径); 2. 名称/标识符命中 `Analyzer#primaryMetricKeywords()` 的物模型,同类中优先该时段有数据的; 3. 第一个有数据的非辅助指标; 4. 第一个非辅助指标;最后兜底物模型列表首项。 **为什么需要第 1 条**:关键词表硬编码在 Java 里,物模型命名不规范时第 2 条整体落空、静默退化为第 3/4 条 ——等于把 `ORDER BY model_order DESC` 的排序结果当主指标。现场实例:轴力计产品因物模型叫"锚力"/"压力"、 关键词只有"轴力/应力",把 GPS"经度"(`model_order` 更靠前)选成了监测指标。 配置入口:`yack-web` 阈值配置页 `views/iot/components/threshold-config.vue` 的「主监测指标」开关, 与阈值同表同行落库,无需额外表。 **读取方式**:不单独查询,直接复用 `ThingsThresholdProvider#find`(`selectByPriority`)逐物模型查回的 阈值行里的 `is_primary` —— 级别口径天然与阈值数值一致,不会出现"标记说它是主指标、阈值数值却取设备行" 的自相矛盾状态。提取逻辑在 `ReportContextBuilder#resolveExplicitPrimary`(包级静态,可单测)。 设备页可见性:本设备未配置该物模型 → 开关旁显示「继承」;本设备已配置但未勾选、而产品级勾了 → 显示「覆盖产品」并提示报告不会用它作主指标(设备优先口径下该勾选确实失效,必须显式告知)。 > 注意此处**不是并集**:同一个物模型两级都配置时,设备行的 `is_primary` 单独决定结果; > 不同物模型各自独立判断(互不影响)。 --- # 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 单节点示例) ```yaml 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 插入默认记录) ```sql -- 先停用云 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:///`;若配置了 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 报告文件路径 ```text /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 天前的对象: ```sh mc ilm rule add local/fastbee --prefix report/ --expire-days 30 ``` 3. 下载实现(推荐后端代理流式下载,可校验权限 + 过期): ```java // 上传(复用现有插件) 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` 直接触发下载,并提示可在历史报表查看。 - 未选设备或时间时按钮禁用。 ```js // 参考实现(新增到 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 设计 ```text POST /iot/report/generate 生成报告(同步,V1) GET /iot/report/list 历史报表(分页,仅未过期) GET /iot/report/download/{reportNo} 下载(校验过期,代理下载) ``` 生成请求(前端两入口的通用格式): ```json 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" } ``` 可选周期预设(后台/后续使用): ```json { "deviceId": 10001, "period": "WEEK", "anchorDate": "2026-08-09", "templateCode": "DEVICE_CRACK_METER_V1" } ``` 响应: ```json { "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" } } ``` 权限: ```java @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` 核心字段: ```sql 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 ```text [ ] 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. 不允许的设计 ```text ❌ 新写 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)。