/// 供水管理相关 API 调用服务 /// 当前使用 mock 数据,后端 API 就绪后替换为真实请求 class WaterService { WaterService._internal(); static final WaterService instance = WaterService._internal(); factory WaterService() => instance; // ==================== Mock 数据 ==================== /// 实时监测数据列表 Future> getMonitorList() async { await Future.delayed(const Duration(milliseconds: 800)); return [ MonitorItem( id: 'M001', name: '1号泵站', type: MonitorType.pumpStation, flow: 120.5, pressure: 0.35, level: null, ph: 7.2, turbidity: 0.8, chlorine: 0.5, status: DeviceStatus.online, updateTime: DateTime.now().subtract(const Duration(minutes: 2)), ), MonitorItem( id: 'M002', name: '2号泵站', type: MonitorType.pumpStation, flow: 98.3, pressure: 0.32, level: null, ph: 7.1, turbidity: 0.6, chlorine: 0.45, status: DeviceStatus.online, updateTime: DateTime.now().subtract(const Duration(minutes: 1)), ), MonitorItem( id: 'M003', name: '3号泵站', type: MonitorType.pumpStation, flow: 0, pressure: 0, level: null, ph: 0, turbidity: 0, chlorine: 0, status: DeviceStatus.offline, updateTime: DateTime.now().subtract(const Duration(hours: 2)), ), MonitorItem( id: 'M004', name: '清水池', type: MonitorType.reservoir, flow: null, pressure: null, level: 4.2, ph: 7.3, turbidity: 0.3, chlorine: 0.4, status: DeviceStatus.online, updateTime: DateTime.now().subtract(const Duration(minutes: 5)), ), MonitorItem( id: 'M005', name: 'DN300主干管', type: MonitorType.pipeline, flow: 285.6, pressure: 0.28, level: null, ph: null, turbidity: null, chlorine: null, status: DeviceStatus.online, updateTime: DateTime.now().subtract(const Duration(minutes: 3)), ), MonitorItem( id: 'M006', name: 'DN200分支管-A区', type: MonitorType.pipeline, flow: 86.2, pressure: 0.22, level: null, ph: null, turbidity: null, chlorine: null, status: DeviceStatus.warning, updateTime: DateTime.now().subtract(const Duration(minutes: 1)), ), MonitorItem( id: 'M007', name: '末梢水质监测点-1', type: MonitorType.quality, flow: null, pressure: 0.15, level: null, ph: 7.0, turbidity: 0.5, chlorine: 0.3, status: DeviceStatus.online, updateTime: DateTime.now().subtract(const Duration(minutes: 10)), ), MonitorItem( id: 'M008', name: '加药间', type: MonitorType.dosing, flow: null, pressure: null, level: 2.8, ph: null, turbidity: null, chlorine: null, status: DeviceStatus.online, updateTime: DateTime.now().subtract(const Duration(minutes: 8)), ), ]; } /// 报警列表 Future> getAlertList({bool unreadOnly = false}) async { await Future.delayed(const Duration(milliseconds: 600)); final alerts = [ AlertItem( id: 'A001', level: AlertLevel.critical, title: '3号泵站设备离线', content: '3号泵站PLC控制器通信中断,已持续2小时,请尽快安排人员现场检查。', location: '3号泵站', deviceName: '3号泵站PLC', isRead: false, createTime: DateTime.now().subtract(const Duration(hours: 2)), handlerName: '待处理', ), AlertItem( id: 'A002', level: AlertLevel.warning, title: 'DN200分支管压力偏低', content: 'A区DN200分支管压力0.22MPa,低于下限0.25MPa,可能存在泄漏或用水量激增。', location: 'A区DN200分支管', deviceName: '压力传感器-P205', isRead: false, createTime: DateTime.now().subtract(const Duration(hours: 1)), handlerName: '待处理', ), AlertItem( id: 'A003', level: AlertLevel.warning, title: '清水池液位接近上限', content: '清水池液位4.2m,接近上限4.5m,建议减少进水量或增加供水。', location: '清水池', deviceName: '液位传感器-L001', isRead: false, createTime: DateTime.now().subtract(const Duration(minutes: 30)), handlerName: '待处理', ), AlertItem( id: 'A004', level: AlertLevel.info, title: '1号泵站例行维护提醒', content: '1号泵站运行时间已达5000小时,建议安排例行保养。', location: '1号泵站', deviceName: '1号泵站主控', isRead: true, createTime: DateTime.now().subtract(const Duration(hours: 5)), handlerName: '王工', ), AlertItem( id: 'A005', level: AlertLevel.critical, title: '出厂水余氯超标', content: '出厂水余氯0.8mg/L,超过国标上限0.8mg/L,请立即调整加药量。', location: '水厂出水口', deviceName: '水质分析仪-WQ001', isRead: true, createTime: DateTime.now().subtract(const Duration(hours: 8)), handlerName: '李工', ), AlertItem( id: 'A006', level: AlertLevel.info, title: '2号泵站变频器固件更新', content: '2号泵站变频器有新固件版本可用(v2.3.1),建议在下次停机时更新。', location: '2号泵站', deviceName: '2号变频器', isRead: true, createTime: DateTime.now().subtract(const Duration(days: 1)), handlerName: '系统', ), ]; if (unreadOnly) { return alerts.where((a) => !a.isRead).toList(); } return alerts; } /// 标记报警为已读 Future markAlertRead(String alertId) async { await Future.delayed(const Duration(milliseconds: 300)); } /// 标记所有报警为已读 Future markAllAlertsRead() async { await Future.delayed(const Duration(milliseconds: 500)); } /// 今日值班信息 Future getTodayDuty() async { await Future.delayed(const Duration(milliseconds: 700)); return DutyInfo( date: DateTime.now(), shiftName: '白班', shiftTime: '08:00 - 20:00', leader: DutyPerson(name: '张建国', phone: '13800138001', role: '值班长'), members: [ DutyPerson(name: '李明', phone: '13800138002', role: '泵站巡检'), DutyPerson(name: '王芳', phone: '13800138003', role: '水质监测'), DutyPerson(name: '赵强', phone: '13800138004', role: '管网维护'), DutyPerson(name: '刘伟', phone: '13800138005', role: '应急抢修'), ], instructions: [ DutyInstruction( id: 'DI001', title: '清水池液位监控', content: '密切关注清水池液位,若超过4.5m立即报告并减少进水量。', time: '08:30', issuer: '调度中心-陈主任', status: InstructionStatus.active, ), DutyInstruction( id: 'DI002', title: '3号泵站故障排查', content: '3号泵站PLC离线,安排刘伟前往现场检查,预计14:00前恢复。', time: '09:15', issuer: '调度中心-陈主任', status: InstructionStatus.inProgress, ), DutyInstruction( id: 'DI003', title: 'A区压力监测', content: 'A区DN200分支管压力偏低,赵强每30分钟上报一次压力数据。', time: '10:00', issuer: '调度中心-陈主任', status: InstructionStatus.active, ), DutyInstruction( id: 'DI004', title: '出厂水余氯检测', content: '每小时对出厂水进行一次余氯检测,确保在0.3-0.8mg/L范围内。', time: '08:00', issuer: '水厂-周厂长', status: InstructionStatus.completed, ), ], ); } /// 水质数据 Future> getQualityData() async { await Future.delayed(const Duration(milliseconds: 900)); return [ QualitySample( id: 'Q001', category: QualityCategory.rawWater, source: '水源地取水口', sampleTime: DateTime.now().subtract(const Duration(hours: 1)), ph: 7.5, turbidity: 12.3, color: 15, odor: '无异味', ammonia: 0.3, permanganate: 3.2, totalColiform: 280, isCompliant: true, ), QualitySample( id: 'Q002', category: QualityCategory.factoryWater, source: '水厂出水口', sampleTime: DateTime.now().subtract(const Duration(hours: 1)), ph: 7.2, turbidity: 0.3, color: 2, odor: '无异味', ammonia: 0.05, permanganate: 1.8, totalColiform: 0, isCompliant: true, ), QualitySample( id: 'Q003', category: QualityCategory.factoryWater, source: '清水池出水', sampleTime: DateTime.now().subtract(const Duration(hours: 2)), ph: 7.1, turbidity: 0.4, color: 3, odor: '无异味', ammonia: 0.08, permanganate: 2.0, totalColiform: 0, isCompliant: true, ), QualitySample( id: 'Q004', category: QualityCategory.endWater, source: 'A区末梢-学校', sampleTime: DateTime.now().subtract(const Duration(hours: 3)), ph: 7.0, turbidity: 0.6, color: 4, odor: '无异味', ammonia: 0.1, permanganate: 2.5, totalColiform: 0, isCompliant: true, ), QualitySample( id: 'Q005', category: QualityCategory.endWater, source: 'B区末梢-医院', sampleTime: DateTime.now().subtract(const Duration(hours: 3)), ph: 6.8, turbidity: 1.2, color: 6, odor: '轻微氯味', ammonia: 0.15, permanganate: 3.0, totalColiform: 2, isCompliant: false, ), QualitySample( id: 'Q006', category: QualityCategory.endWater, source: 'C区末梢-居民区', sampleTime: DateTime.now().subtract(const Duration(hours: 4)), ph: 7.1, turbidity: 0.5, color: 3, odor: '无异味', ammonia: 0.08, permanganate: 2.2, totalColiform: 0, isCompliant: true, ), ]; } } // ==================== 数据模型 ==================== /// 监测类型 enum MonitorType { pumpStation('泵站'), reservoir('水池/水箱'), pipeline('管网'), quality('水质监测点'), dosing('加药间'); final String label; const MonitorType(this.label); } /// 设备状态 enum DeviceStatus { online('在线', Color(0xFF4CAF50)), offline('离线', Color(0xFF9E9E9E)), warning('告警', Color(0xFFFF9800)), error('故障', Color(0xFFF44336)); final String label; final int color; const DeviceStatus(this.label, this.color); } /// 监测数据项 class MonitorItem { final String id; final String name; final MonitorType type; final double? flow; // 流量 m³/h final double? pressure; // 压力 MPa final double? level; // 液位 m final double? ph; final double? turbidity; // 浊度 NTU final double? chlorine; // 余氯 mg/L final DeviceStatus status; final DateTime updateTime; const MonitorItem({ required this.id, required this.name, required this.type, this.flow, this.pressure, this.level, this.ph, this.turbidity, this.chlorine, required this.status, required this.updateTime, }); String get statusLabel => status.label; } /// 报警级别 enum AlertLevel { critical('严重', Color(0xFFF44336)), warning('警告', Color(0xFFFF9800)), info('提示', Color(0xFF2196F3)); final String label; final int color; const AlertLevel(this.label, this.color); } /// 报警项 class AlertItem { final String id; final AlertLevel level; final String title; final String content; final String location; final String deviceName; bool isRead; final DateTime createTime; final String handlerName; AlertItem({ required this.id, required this.level, required this.title, required this.content, required this.location, required this.deviceName, required this.isRead, required this.createTime, required this.handlerName, }); } /// 值班人员 class DutyPerson { final String name; final String phone; final String role; const DutyPerson({ required this.name, required this.phone, required this.role, }); } /// 指令状态 enum InstructionStatus { active('待执行', Color(0xFFFF9800)), inProgress('执行中', Color(0xFF2196F3)), completed('已完成', Color(0xFF4CAF50)); final String label; final int color; const InstructionStatus(this.label, this.color); } /// 调度指令 class DutyInstruction { final String id; final String title; final String content; final String time; final String issuer; final InstructionStatus status; const DutyInstruction({ required this.id, required this.title, required this.content, required this.time, required this.issuer, required this.status, }); } /// 今日值班信息 class DutyInfo { final DateTime date; final String shiftName; final String shiftTime; final DutyPerson leader; final List members; final List instructions; const DutyInfo({ required this.date, required this.shiftName, required this.shiftTime, required this.leader, required this.members, required this.instructions, }); } /// 水质类别 enum QualityCategory { rawWater('原水'), factoryWater('出厂水'), endWater('末梢水'); final String label; const QualityCategory(this.label); } /// 水质采样数据 class QualitySample { final String id; final QualityCategory category; final String source; final DateTime sampleTime; final double ph; final double turbidity; // NTU final int color; // 色度 final String odor; // 嗅味 final double ammonia; // 氨氮 mg/L final double permanganate; // 高锰酸盐指数 mg/L final int totalColiform; // 总大肠菌群 CFU/100mL final bool isCompliant; const QualitySample({ required this.id, required this.category, required this.source, required this.sampleTime, required this.ph, required this.turbidity, required this.color, required this.odor, required this.ammonia, required this.permanganate, required this.totalColiform, required this.isCompliant, }); /// 获取各指标达标情况 List getIndicators() { return [ QualityIndicator('pH', ph.toStringAsFixed(1), '6.5-8.5', ph >= 6.5 && ph <= 8.5), QualityIndicator('浊度', '${turbidity.toStringAsFixed(1)} NTU', '≤1 NTU', turbidity <= 1.0), QualityIndicator('色度', '$color 度', '≤15 度', color <= 15), QualityIndicator('嗅味', odor, '无异味', odor == '无异味'), QualityIndicator('氨氮', '${ammonia.toStringAsFixed(2)} mg/L', '≤0.5 mg/L', ammonia <= 0.5), QualityIndicator('高锰酸盐', '${permanganate.toStringAsFixed(1)} mg/L', '≤3 mg/L', category == QualityCategory.rawWater ? true : permanganate <= 3.0), QualityIndicator('总大肠菌群', '$totalColiform CFU/100mL', category == QualityCategory.rawWater ? '≤1000' : '不得检出', category == QualityCategory.rawWater ? totalColiform <= 1000 : totalColiform == 0), ]; } } /// 水质指标 class QualityIndicator { final String name; final String value; final String standard; final bool isCompliant; const QualityIndicator(this.name, this.value, this.standard, this.isCompliant); }