import 'package:flutter/material.dart'; /// 今日调度页面 class DispatchPage extends StatefulWidget { const DispatchPage({super.key}); @override State createState() => _DispatchPageState(); } class _DispatchPageState extends State with AutomaticKeepAliveClientMixin { @override bool get wantKeepAlive => true; @override Widget build(BuildContext context) { super.build(context); return Scaffold( appBar: AppBar( title: const Text('今日调度'), actions: [ IconButton( icon: const Icon(Icons.calendar_today), onPressed: () {}, ), ], ), body: const Column( children: [ Expanded( child: SingleChildScrollView( padding: EdgeInsets.all(16), child: Column( children: [ _ShiftOverviewCard(), SizedBox(height: 16), _DutyPersonnelList(), SizedBox(height: 16), _DispatchCommandsCard(), SizedBox(height: 16), _EmergencyContactsCard(), ], ), ), ), ], ), ); } } /// 班次概览卡片 class _ShiftOverviewCard extends StatelessWidget { const _ShiftOverviewCard(); @override Widget build(BuildContext context) { return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.access_time, color: Color(0xFF1976D2)), const SizedBox(width: 8), const Text( '班次概览', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const Spacer(), Text( '2026-06-17', style: TextStyle( fontSize: 14, color: Colors.grey[600], ), ), ], ), const SizedBox(height: 16), _buildShiftRow('早班 (06:00-14:00)', '3/4 在岗', Colors.green), const SizedBox(height: 8), _buildShiftRow('中班 (14:00-22:00)', '2/3 在岗', Colors.orange), const SizedBox(height: 8), _buildShiftRow('夜班 (22:00-06:00)', '2/3 在岗', Colors.blue), ], ), ), ); } Widget _buildShiftRow(String shift, String status, Color color) { return Row( children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(16), border: Border.all(color: color), ), child: Text( shift, style: TextStyle( fontSize: 13, color: color, fontWeight: FontWeight.w500, ), ), ), const SizedBox(width: 12), Expanded( child: Text( status, style: const TextStyle(fontSize: 14), ), ), ], ); } } /// 值班人员列表 class _DutyPersonnelList extends StatelessWidget { const _DutyPersonnelList(); @override Widget build(BuildContext context) { final personnel = [ {'name': '张明', 'role': '值班长', 'station': '城东加压站', 'status': '在岗', 'phone': '138****1234'}, {'name': '李强', 'role': '技术员', 'station': '城西水厂', 'status': '在岗', 'phone': '139****5678'}, {'name': '王芳', 'role': '操作员', 'station': '南区配水站', 'status': '休息', 'phone': '137****9012'}, {'name': '赵刚', 'role': '安全员', 'station': '北区调蓄池', 'status': '在岗', 'phone': '136****3456'}, {'name': '刘洋', 'role': '技术员', 'station': '中心泵站', 'status': '在岗', 'phone': '135****7890'}, ]; return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.people, color: Color(0xFF1976D2)), const SizedBox(width: 8), const Text( '值班人员', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ], ), const SizedBox(height: 12), ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: personnel.length, itemBuilder: (context, index) { final person = personnel[index]; return _buildPersonnelItem(person); }, ), ], ), ), ); } Widget _buildPersonnelItem(Map person) { final isWorking = person['status'] == '在岗'; return Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( children: [ Container( width: 40, height: 40, decoration: BoxDecoration( color: isWorking ? Colors.green.withOpacity(0.1) : Colors.grey.withOpacity(0.1), borderRadius: BorderRadius.circular(20), border: Border.all( color: isWorking ? Colors.green : Colors.grey, ), ), child: Icon( isWorking ? Icons.person : Icons.person_off, color: isWorking ? Colors.green : Colors.grey, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( person['name'], style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: isWorking ? Colors.green.withOpacity(0.1) : Colors.grey.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: Text( person['status'], style: TextStyle( fontSize: 12, color: isWorking ? Colors.green : Colors.grey, ), ), ), ], ), const SizedBox(height: 4), Text( '${person['role']} · ${person['station']}', style: TextStyle( fontSize: 13, color: Colors.grey[600], ), ), ], ), ), if (isWorking) IconButton( icon: const Icon(Icons.phone, color: Color(0xFF1976D2)), onPressed: () { // 拨打电话逻辑 }, ), ], ), ); } } /// 调度指令卡片 class _DispatchCommandsCard extends StatelessWidget { const _DispatchCommandsCard(); @override Widget build(BuildContext context) { final commands = [ { 'id': 'CMD-001', 'type': '设备启停', 'target': '城东加压站 #2泵', 'status': '执行中', 'operator': '张明', 'time': '08:30', }, { 'id': 'CMD-002', 'type': '参数调整', 'target': '城西水厂出水压力', 'status': '已完成', 'operator': '李强', 'time': '09:15', }, { 'id': 'CMD-003', 'type': '故障处理', 'target': '北区调蓄池传感器', 'status': '待处理', 'operator': '赵刚', 'time': '10:20', }, ]; return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.assignment, color: Color(0xFF1976D2)), const SizedBox(width: 8), const Text( '调度指令', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ], ), const SizedBox(height: 12), ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: commands.length, itemBuilder: (context, index) { final command = commands[index]; return _buildCommandItem(command); }, ), ], ), ), ); } Widget _buildCommandItem(Map command) { Color statusColor; switch (command['status']) { case '执行中': statusColor = Colors.orange; break; case '已完成': statusColor = Colors.green; break; case '待处理': statusColor = Colors.red; break; default: statusColor = Colors.grey; } return Padding( padding: const EdgeInsets.only(bottom: 12), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( border: Border.all(color: Colors.grey[300]!), borderRadius: BorderRadius.circular(8), ), child: Row( children: [ Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: statusColor.withOpacity(0.1), borderRadius: BorderRadius.circular(4), ), child: Icon( _getCommandIcon(command['type']), color: statusColor, size: 16, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( command['type'], style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w500, ), ), Text( command['target'], style: TextStyle( fontSize: 13, color: Colors.grey[600], ), ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: statusColor.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Text( command['status'], style: TextStyle( fontSize: 11, color: statusColor, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 4), Text( '${command['time']} · ${command['operator']}', style: TextStyle( fontSize: 11, color: Colors.grey[500], ), ), ], ), ], ), ), ); } IconData _getCommandIcon(String type) { switch (type) { case '设备启停': return Icons.power_settings_new; case '参数调整': return Icons.tune; case '故障处理': return build; default: return Icons.assignment; } } } /// 紧急联系人卡片 class _EmergencyContactsCard extends StatelessWidget { const _EmergencyContactsCard(); @override Widget build(BuildContext context) { final contacts = [ {'name': '应急指挥中心', 'phone': '119', 'type': '消防'}, {'name': '抢修热线', 'phone': '96116', 'type': '抢修'}, {'name': '技术支持', 'phone': '400-123-4567', 'type': '技术'}, {'name': '环保举报', 'phone': '12369', 'type': '环保'}, ]; return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.phone_in_talk, color: Color(0xFF1976D2)), const SizedBox(width: 8), const Text( '紧急联系人', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ], ), const SizedBox(height: 12), ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: contacts.length, itemBuilder: (context, index) { final contact = contacts[index]; return _buildContactItem(contact); }, ), ], ), ), ); } Widget _buildContactItem(Map contact) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Row( children: [ Container( width: 32, height: 32, decoration: BoxDecoration( color: Colors.red.withOpacity(0.1), borderRadius: BorderRadius.circular(16), ), child: Icon( Icons.phone, color: Colors.red, size: 16, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( contact['name'], style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w500, ), ), Text( '${contact['type']} · ${contact['phone']}', style: TextStyle( fontSize: 13, color: Colors.grey[600], ), ), ], ), ), IconButton( icon: const Icon(Icons.call), color: Colors.red, onPressed: () { // 拨打电话逻辑 }, ), ], ), ); } }