2026-09-11 按用户参考图重做 /water-devices:四项统计、组合筛选、每页8张设备卡片、设备详情/编辑、固件版本分布、近30日用水趋势和异常类型表。所有数量取数据库;没有套用图片中的1302台等示例值。
WaterDeviceDashboard:Eloquent 读模型,负责全量统计、设备分页、版本分布、趋势、异常和完整导出。控制器只授权并封装响应。service/device/DeviceFilters:查询条件值对象,列表和导出共用校验及筛选。service/device/DeviceStatusPolicy:互斥状态策略,计数、筛选、卡片、导出使用相同规则。WaterBusiness::save('device', ...) 保存;上报仍经过 DeviceReport,不在页面或控制器复制写库逻辑。useDeviceDashboard.ts 管理查询条件、已应用条件、分页、错误及旧响应丢弃;页面只组合组件。DeviceCard、DeviceEditor、DeviceAnalytics、FirmwareDialog 各自负责卡片、表单、图表和版本入口。WaterMetricCards、useWaterOptions、waterDownload 分别提供可复用统计卡、远程选项及校验后下载,样式限定组件/设备页面范围。新增模型 WaterDeviceUsage,表 sa_water_device_usage,唯一键 (device_id, day),按日索引。执行:
php scripts/migrate_water_device_usage.php --apply
脚本只建新表并以 INSERT IGNORE 复制已有日期明确的设备用水快照,重跑不覆盖历史;此次实际复制0条,没有制造往日用量,旧设备/库存/权益保持不变。部署顺序为迁移先于开启新页面和上报代码。
DeviceReport 在原设备行锁和事务内保存每天累计最大值,重复/较小乱序报告不累加;跨日使用新日期行,旧日期保留。报告验证、HTTP/MQTT关闭默认值和供应商适配接口不变。无厂商协议时不启用采集;参见 WATER_DEVICE_INTEGRATION.md。
趋势返回今天及前29天;有上报则汇总各设备日累计值和上报设备数,无记录日期为 null,不伪装为0或连接空白区间。当前无历史数据时显示真实空状态,未来正常上报后自动积累。
GET /core/water/devices/dashboard:keyword/status/region/firmware/page/limit;默认8条,最多100条;返回 summary/list/options/trend/anomalies/updated_at。POST /core/water/devices/export:相同筛选,忽略分页,导出全部匹配设备XLSX;超过50,000条明确拒绝。文本公式前缀转义,临时文件清理。water:devices:read;原写接口继续需 water:devices:write。未授权不能通过直接调用导出绕过权限。php -d extension=mbstring tests/water_device_dashboard_test.php --http:45项,包括分页、状态边界/优先级、筛选、统计、零值/缺失值、日期边界、日累计去重、XLSX、权限及真实本地HTTP。临时设备、用水记录和关联档案全部回滚,HTTP只读/导出。water_device_ingress_test.php 30项通过;未启用HTTP/MQTT网关。failed to start Node runtime: 系统找不到指定的路径。 (os error 3);未完成截图和实际浏览器交互验收,不将类型/构建/API测试视为视觉通过。回退页面可恢复 <WaterWorkspace module="devices" />。回退上报代码应保留新日汇总表,避免丢失已经积累的用水历史。