From 915417461408df497a93b08cdf6e875ccaf592a2 Mon Sep 17 00:00:00 2001 From: Songzex <2402265378@qq.com> Date: Fri, 29 May 2026 14:14:19 +0800 Subject: [PATCH] =?UTF-8?q?=E9=81=97=E6=BC=8F=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../widgets/drone_station_item_card.dart | 504 +++++++++++++----- pubspec.yaml | 2 +- 2 files changed, 377 insertions(+), 129 deletions(-) diff --git a/lib/features/v2/device_list/presentation/widgets/drone_station_item_card.dart b/lib/features/v2/device_list/presentation/widgets/drone_station_item_card.dart index 2b9b8d7e..272dde3b 100644 --- a/lib/features/v2/device_list/presentation/widgets/drone_station_item_card.dart +++ b/lib/features/v2/device_list/presentation/widgets/drone_station_item_card.dart @@ -1,15 +1,15 @@ import 'package:flutter/material.dart'; +import '../../domain/entities/drone_station_entity.dart'; + /// 无人机机场列表项卡片 class DroneStationItemCard extends StatelessWidget { - final String name; - final String id; + final DroneStationEntity station; final VoidCallback onTap; const DroneStationItemCard({ super.key, - required this.name, - required this.id, + required this.station, required this.onTap, }); @@ -18,100 +18,409 @@ class DroneStationItemCard extends StatelessWidget { return GestureDetector( onTap: onTap, child: Container( - margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), - padding: const EdgeInsets.all(16), + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: const [ + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [Colors.white, const Color(0xFFF8F9FA)], + ), + borderRadius: BorderRadius.circular(16), + boxShadow: [ BoxShadow( - color: Color(0x0D000000), - blurRadius: 8, - offset: Offset(0, 2), + color: Colors.black.withOpacity(0.08), + blurRadius: 12, + offset: const Offset(0, 4), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - '机场状态', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Color(0xFF1D2129), + // 顶部标题栏 + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + const Color(0xFF165DFF).withOpacity(0.05), + const Color(0xFF165DFF).withOpacity(0.02), + ], + ), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ), + child: Row( + children: [ + // 图标 + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: const Color(0xFF165DFF).withOpacity(0.1), + borderRadius: BorderRadius.circular(10), + ), + child: const Icon( + Icons.home_max_rounded, + color: Color(0xFF165DFF), + size: 24, + ), + ), + const SizedBox(width: 12), + // 名称 + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + station.callsign.isNotEmpty + ? station.callsign + : '未知机场', + style: const TextStyle( + fontSize: 17, + fontWeight: FontWeight.bold, + color: Color(0xFF1D2129), + ), + ), + const SizedBox(height: 2), + Text( + 'SN: ${station.deviceSn}', + style: const TextStyle( + fontSize: 11, + color: Color(0xFF86909C), + ), + ), + ], + ), + ), + // 机场状态徽章 + _buildStatusBadge('机场', station.isOnline), + ], + ), + ), + + const Divider(height: 1, color: Color(0xFFE5E6EB)), + + Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 机场基础信息卡片 + _buildSectionCard( + title: '机场信息', + icon: Icons.settings_rounded, + children: [ + _buildInfoRowWithIcon( + Icons.tag_rounded, + '机场序列号', + station.deviceSn, + ), + const SizedBox(height: 10), + _buildInfoRowWithIcon( + Icons.router_rounded, + '网关序列号', + station.gatewaySn, + ), + // if (station.latitude != null || station.longitude != null) ...[ + // const SizedBox(height: 10), + // _buildInfoRowWithIcon( + // Icons.location_on_rounded, + // '位置坐标', + // station.latitude != null && station.longitude != null + // ? '${station.latitude}, ${station.longitude}' + // : '未知', + // ), + // ], + ], + ), + // + // const SizedBox(height: 12), + // + // // 电量卡片 + // _buildInfoCard( + // title: '电量状态', + // icon: Icons.battery_full_rounded, + // iconColor: _getBatteryColor(station.capacityPercent), + // value: station.capacityPercent != null ? '${station.capacityPercent}%' : '未知', + // progressValue: station.capacityPercent, + // ), + // + // const SizedBox(height: 12), + // + // // 环境信息卡片 + // _buildSectionCard( + // title: '环境监测', + // icon: Icons.thermostat_rounded, + // children: [ + // _buildInfoRowWithIcon( + // Icons.thermostat_rounded, + // '环境温度', + // station.environmentTemperature != null ? '${station.environmentTemperature}°C' : '未知', + // ), + // const SizedBox(height: 10), + // _buildInfoRowWithIcon( + // Icons.air_rounded, + // '风速', + // station.windSpeed != null ? '${station.windSpeed} m/s' : '未知', + // ), + // const SizedBox(height: 10), + // _buildInfoRowWithIcon( + // Icons.water_drop_rounded, + // '降雨量', + // station.rainfall != null ? '${station.rainfall} mm' : '未知', + // ), + // ], + // ), + // + // const SizedBox(height: 12), + // + // // 网络状态卡片 + // _buildSectionCard( + // title: '网络状态', + // icon: Icons.wifi_rounded, + // children: [ + // _buildInfoRowWithIcon( + // Icons.network_check_rounded, + // '网络状态', + // station.networkState != null ? '等级 ${station.networkState}' : '未知', + // ), + // const SizedBox(height: 10), + // _buildInfoRowWithIcon( + // Icons.gps_fixed_rounded, + // '位置状态', + // station.positionState != null ? '状态 ${station.positionState}' : '未知', + // ), + // ], + // ), + // + // + // // 摄像头信息 + // if (station.gatewayCameraList != null && station.gatewayCameraList!.isNotEmpty) ...[ + // const SizedBox(height: 12), + // _buildSectionCard( + // title: '网关摄像头', + // icon: Icons.videocam_rounded, + // children: [ + // ...station.gatewayCameraList!.map((camera) => Padding( + // padding: const EdgeInsets.only(bottom: 8), + // child: _buildInfoRowWithIcon( + // Icons.camera_alt_rounded, + // '摄像头 ${camera.cameraIndex}', + // camera.cameraPosition, + // ), + // )), + // ], + // ), + // ], + ], ), ), - const SizedBox(height: 16), - _buildStatusRow('机场编号', 'AIRPORT-01', status: '正常'), - const SizedBox(height: 12), - _buildStatusRow('位置', '升压站旁 - 无人机机场'), - const SizedBox(height: 12), - _buildStatusRow('舱门状态', '关闭', status: '正常'), - const SizedBox(height: 12), - _buildStatusRowWithProgress('充电状态', '充电中', '85%'), - const SizedBox(height: 12), - _buildWeatherRow(), - const SizedBox(height: 12), - _buildStatusRow('网络状态', '4G/5G 强'), ], ), ), ); } - /// 状态行(带状态标签) - Widget _buildStatusRow(String label, String value, {String? status}) { - return Row( - children: [ - Text( - label, - style: const TextStyle( - fontSize: 13, - color: Color(0xFF86909C), - ), + /// 状态徽章 + Widget _buildStatusBadge(String label, bool isOnline) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: isOnline + ? [const Color(0xFF00B42A), const Color(0xFF23C343)] + : [const Color(0xFFF53F3F), const Color(0xFFF76560)], ), - const Spacer(), - Text( - value, - style: const TextStyle( - fontSize: 13, - color: Color(0xFF1D2129), - fontWeight: FontWeight.w500, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: + (isOnline ? const Color(0xFF00B42A) : const Color(0xFFF53F3F)) + .withOpacity(0.3), + blurRadius: 6, + offset: const Offset(0, 2), ), - ), - if (status != null) ...[ - const SizedBox(width: 8), + ], + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: const Color(0xFF00B42A).withOpacity(0.1), - borderRadius: BorderRadius.circular(4), + width: 6, + height: 6, + decoration: const BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, ), - child: Text( - status, - style: const TextStyle( - fontSize: 11, - color: Color(0xFF00B42A), - fontWeight: FontWeight.w500, - ), + ), + const SizedBox(width: 5), + Text( + '$label\n${isOnline ? '在线' : '离线'}', + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 10, + color: Colors.white, + fontWeight: FontWeight.w600, + height: 1.1, ), ), ], + ), + ); + } + + /// 信息卡片(带进度条) + Widget _buildInfoCard({ + required String title, + required IconData icon, + required Color iconColor, + required String value, + double? progressValue, + }) { + return Container( + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.04), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(icon, size: 18, color: iconColor), + const SizedBox(width: 6), + Text( + title, + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w600, + color: Color(0xFF4E5969), + ), + ), + const Spacer(), + Text( + value, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: iconColor, + ), + ), + ], + ), + if (progressValue != null) ...[ + const SizedBox(height: 10), + ClipRRect( + borderRadius: BorderRadius.circular(6), + child: LinearProgressIndicator( + value: progressValue / 100, + backgroundColor: const Color(0xFFE5E6EB), + valueColor: AlwaysStoppedAnimation(iconColor), + minHeight: 8, + ), + ), + ], + ], + ), + ); + } + + /// 区块卡片 + Widget _buildSectionCard({ + required String title, + required IconData icon, + required List children, + }) { + return Container( + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.04), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(icon, size: 18, color: const Color(0xFF165DFF)), + const SizedBox(width: 6), + Text( + title, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF1D2129), + ), + ), + ], + ), + const SizedBox(height: 12), + ...children, + ], + ), + ); + } + + /// 信息行(带图标) + Widget _buildInfoRowWithIcon(IconData icon, String label, String value) { + return Row( + children: [ + Icon(icon, size: 16, color: const Color(0xFF86909C)), + const SizedBox(width: 8), + SizedBox( + width: 70, + child: Text( + '$label:', + style: const TextStyle(fontSize: 11, color: Color(0xFF86909C)), + ), + ), + const SizedBox(width: 4), + Expanded( + child: Text( + value, + style: const TextStyle( + fontSize: 12, + color: Color(0xFF1D2129), + fontWeight: FontWeight.w500, + ), + ), + ), ], ); } - /// 带进度条的状态行 - Widget _buildStatusRowWithProgress(String label, String value, String progress) { + /// 获取电量颜色 + Color _getBatteryColor(double? percent) { + if (percent == null) return const Color(0xFF86909C); + if (percent >= 60) return const Color(0xFF00B42A); + if (percent >= 30) return const Color(0xFFFF7D00); + return const Color(0xFFF53F3F); + } + + /// 信息行(旧版,保留兼容) + Widget _buildInfoRow(String label, String value) { return Row( children: [ Text( label, - style: const TextStyle( - fontSize: 13, - color: Color(0xFF86909C), - ), + style: const TextStyle(fontSize: 13, color: Color(0xFF86909C)), ), const Spacer(), Text( @@ -122,67 +431,6 @@ class DroneStationItemCard extends StatelessWidget { fontWeight: FontWeight.w500, ), ), - const SizedBox(width: 8), - Text( - progress, - style: const TextStyle( - fontSize: 13, - color: Color(0xFF165DFF), - fontWeight: FontWeight.w600, - ), - ), - const SizedBox(width: 4), - const Icon( - Icons.arrow_forward_ios, - size: 12, - color: Color(0xFF86909C), - ), - ], - ); - } - - /// 气象条件行 - Widget _buildWeatherRow() { - return Row( - children: [ - const Text( - '气象条件', - style: TextStyle( - fontSize: 13, - color: Color(0xFF86909C), - ), - ), - const Spacer(), - Row( - children: [ - const Icon(Icons.wb_sunny, size: 16, color: Color(0xFFFF7D00)), - const SizedBox(width: 4), - const Text( - '晴', - style: TextStyle( - fontSize: 13, - color: Color(0xFF1D2129), - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(width: 8), - const Text( - '25°C', - style: TextStyle( - fontSize: 13, - color: Color(0xFF1D2129), - ), - ), - const SizedBox(width: 8), - const Text( - '东南风 2级', - style: TextStyle( - fontSize: 13, - color: Color(0xFF1D2129), - ), - ), - ], - ), ], ); } diff --git a/pubspec.yaml b/pubspec.yaml index 27670875..e714d888 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.1.2+2 +version: 1.0.0+1 flutter_icons: android: "launcher_icon"