diff --git a/lib/modules/agent/views/music_card.dart b/lib/modules/agent/views/music_card.dart index e00cb158a..761d66580 100644 --- a/lib/modules/agent/views/music_card.dart +++ b/lib/modules/agent/views/music_card.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../../../routes/app_routes.dart'; import '../controllers/agent_controller.dart'; @@ -20,10 +21,10 @@ Widget buildMusicItem(BuildContext context, int id, String name, String url, controller.musicStatus(); //刷新状态 return Container( - padding: const EdgeInsets.all(14), + padding: EdgeInsets.all(14.w), decoration: BoxDecoration( color: isDarkMode ? const Color(0xFF1E1E1E) : Colors.white, - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(12.r), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: isDarkMode ? 0.2 : 0.03), @@ -36,11 +37,11 @@ Widget buildMusicItem(BuildContext context, int id, String name, String url, child: Row( children: [ Container( - width: 50, - height: 50, + width: 50.w, + height: 50.h, decoration: BoxDecoration( - color: Colors.grey[100], - borderRadius: BorderRadius.circular(8), + color: isDarkMode ? Colors.grey[800] : Colors.grey[100], + borderRadius: BorderRadius.circular(8.r), image: image.isNotEmpty ? DecorationImage( image: NetworkImage(image), @@ -51,12 +52,12 @@ Widget buildMusicItem(BuildContext context, int id, String name, String url, child: image.isEmpty ? Icon( Icons.music_note, - size: 18, + size: 18.sp, color: Theme.of(context).primaryColor, ) : null, ), - const SizedBox(width: 12), + SizedBox(width: 12.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -64,18 +65,18 @@ Widget buildMusicItem(BuildContext context, int id, String name, String url, Text( name, style: TextStyle( - fontSize: 13, + fontSize: 13.sp, fontWeight: FontWeight.w500, - color: Colors.grey[800], + color: isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.grey[800], ), overflow: TextOverflow.ellipsis, ), - SizedBox(height: 2), + SizedBox(height: 2.h), Text( singer, style: TextStyle( - fontSize: 12, - color: Colors.grey[600], + fontSize: 12.sp, + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], ), overflow: TextOverflow.ellipsis, ), diff --git a/lib/modules/agent/views/navigation_card.dart b/lib/modules/agent/views/navigation_card.dart index 0ad88dfe3..2f79869c8 100644 --- a/lib/modules/agent/views/navigation_card.dart +++ b/lib/modules/agent/views/navigation_card.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../controllers/agent_controller.dart'; @@ -42,16 +43,18 @@ Widget navigationCard( }) { int currentIndex = 0; final controller = Get.find(); // 获取控制器 + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + return Container( - height: height, + height: height.h, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - color: Colors.white, - boxShadow: const [ + borderRadius: BorderRadius.circular(16.r), + color: isDarkMode ? const Color(0xFF1E1E1E) : Colors.white, + boxShadow: [ BoxShadow( blurRadius: 8, - color: Colors.black12, - offset: Offset(0, 4), + color: Colors.black.withValues(alpha: isDarkMode ? 0.3 : 0.12), + offset: const Offset(0, 4), ), ], ), @@ -63,13 +66,13 @@ Widget navigationCard( // 路线图片 ClipRRect( borderRadius: - const BorderRadius.vertical(top: Radius.circular(16)), + BorderRadius.vertical(top: Radius.circular(16.r)), child: AnimatedSwitcher( duration: const Duration(milliseconds: 300), child: Image.network( modes[currentIndex]["image"] as String, key: ValueKey(modes[currentIndex]["ntype"] as String), - height: 160, + height: 160.h, width: double.infinity, fit: BoxFit.cover, ), @@ -78,7 +81,7 @@ Widget navigationCard( // 导航方式切换按钮 Padding( - padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), + padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: List.generate(modes.length, (index) { @@ -90,17 +93,17 @@ Widget navigationCard( } : null, child: SizedBox( - width: 50, + width: 50.w, child: Text( (modes[index]["ntype"] as String).tr, textAlign: TextAlign.center, style: TextStyle( color: modes[index]['enable'] ? isSelected - ? Colors.blue - : Colors.black87 + ? Theme.of(context).primaryColor + : isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87 : Colors.grey, - fontSize: 12, + fontSize: 12.sp, fontWeight: FontWeight.w500, ), ), @@ -112,35 +115,36 @@ Widget navigationCard( // 距离和耗时 Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), + padding: EdgeInsets.symmetric(horizontal: 8.w), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('$destination', - style: const TextStyle( - fontSize: 12, color: Colors.black)), + Text(destination, + style: TextStyle( + fontSize: 12.sp, + color: isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87)), Text( '${formatDistance(modes[currentIndex]["distance"])}-约${formatDuration(modes[currentIndex]["duration"])}', - style: const TextStyle( - fontSize: 15, color: Colors.blue)), + style: TextStyle( + fontSize: 15.sp, + color: Theme.of(context).primaryColor)), if (navigation != null) Text( "导航中... ${navigation["distanceText"]}进入${navigation["nextRoad"]}", style: TextStyle( - fontSize: 12, - color: - const Color.fromARGB(255, 164, 164, 164))) + fontSize: 12.sp, + color: isDarkMode ? Colors.grey[400] : Colors.grey[600])) ], ), CircleAvatar( - backgroundColor: Colors.blue, - radius: 18, + backgroundColor: Theme.of(context).primaryColor, + radius: 18.r, child: IconButton( - icon: const Icon(Icons.turn_left, - color: Colors.white, size: 20), + icon: Icon(Icons.turn_left, + color: Colors.white, size: 20.sp), onPressed: () { controller.openNavigation(start, end, ""); }, diff --git a/lib/modules/agent/views/travel_card.dart b/lib/modules/agent/views/travel_card.dart index e5c01a163..be62ccda7 100644 --- a/lib/modules/agent/views/travel_card.dart +++ b/lib/modules/agent/views/travel_card.dart @@ -1,29 +1,32 @@ import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; /// 构建旅游内容卡片 Widget buildTravelContent( BuildContext context, List> travellist) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - '以下是一些推搜索结果:', + Text( + '以下是一些推荐搜索结果:', style: TextStyle( - color: Colors.black87, - fontSize: 14, + color: isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87, + fontSize: 14.sp, height: 1.4, fontWeight: FontWeight.w400, ), ), - const SizedBox(height: 12), + SizedBox(height: 12.h), Container( - padding: const EdgeInsets.all(12), + padding: EdgeInsets.all(12.w), decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), + color: isDarkMode ? const Color(0xFF1E1E1E) : Colors.white, + borderRadius: BorderRadius.circular(12.r), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.03), + color: Colors.black.withValues(alpha: isDarkMode ? 0.2 : 0.03), blurRadius: 3, spreadRadius: 1, offset: const Offset(0, 1), @@ -53,16 +56,16 @@ Widget buildTravelContent( // ), // const SizedBox(height: 10), - // 动态生成音乐条目 + // 动态生成旅游景点条目 ...travellist.asMap().entries.map((entry) { final index = entry.key; final item = entry.value; - final name = item["name"] ?? "未知歌曲"; //名字 + final name = item["name"] ?? "未知景点"; //名字 final addr = item["addr"] ?? ""; //地址 - final tag = item["tag"] ?? "未知歌手"; //标签 - final rating = item["rating"] ?? ""; //评分 - final distance = item["distance"] ?? ""; //距离 - final images = item["images"] ?? []; // 图片列表 + // final tag = item["tag"] ?? "未知标签"; //标签 + // final rating = item["rating"] ?? ""; //评分 + // final distance = item["distance"] ?? ""; //距离 + // final images = item["images"] ?? []; // 图片列表 return Column( children: [ buildLocationItem( @@ -71,7 +74,11 @@ Widget buildTravelContent( addr, ), if (index != travellist.length - 1) - Divider(height: 1, thickness: 1, color: Colors.grey[100]), + Divider( + height: 1.h, + thickness: 1, + color: isDarkMode ? Colors.grey[700] : Colors.grey[100] + ), ], ); }).toList(), @@ -82,19 +89,19 @@ Widget buildTravelContent( // Divider(height: 1, thickness: 1, color: Colors.grey[100]), // _buildLocationItem('浅草寺', '东京最古老的寺庙', context), - const SizedBox(height: 8), + SizedBox(height: 8.h), Center( child: TextButton( onPressed: () {}, style: TextButton.styleFrom( minimumSize: Size.zero, - padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h), tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), child: Text( '查看更多景点', style: TextStyle( - fontSize: 12, + fontSize: 12.sp, color: Theme.of(context).primaryColor, fontWeight: FontWeight.w500, ), @@ -104,41 +111,41 @@ Widget buildTravelContent( ], ), ), - const SizedBox(height: 10), + SizedBox(height: 10.h), Row( mainAxisSize: MainAxisSize.min, children: [ Expanded( child: OutlinedButton.icon( onPressed: () {}, - icon: Icon(Icons.map, size: 16), - label: Text('查看地图'), + icon: Icon(Icons.map, size: 16.sp), + label: const Text('查看地图'), style: OutlinedButton.styleFrom( foregroundColor: Theme.of(context).primaryColor, side: BorderSide( - color: Theme.of(context).primaryColor.withOpacity(0.5)), - padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), + color: Theme.of(context).primaryColor.withValues(alpha: 0.5)), + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.circular(16.r), ), - textStyle: TextStyle(fontSize: 12), + textStyle: TextStyle(fontSize: 12.sp), ), ), ), - SizedBox(width: 8), + SizedBox(width: 8.w), Expanded( child: OutlinedButton.icon( onPressed: () {}, - icon: Icon(Icons.bookmark_border, size: 16), - label: Text('保存到收藏'), + icon: Icon(Icons.bookmark_border, size: 16.sp), + label: const Text('保存到收藏'), style: OutlinedButton.styleFrom( - foregroundColor: Colors.grey[700], - side: BorderSide(color: Colors.grey[400]!), - padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), + foregroundColor: isDarkMode ? Colors.grey[400] : Colors.grey[700], + side: BorderSide(color: isDarkMode ? Colors.grey[600]! : Colors.grey[400]!), + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.circular(16.r), ), - textStyle: TextStyle(fontSize: 12), + textStyle: TextStyle(fontSize: 12.sp), ), ), ), @@ -154,23 +161,25 @@ Widget buildLocationItem( final isDarkMode = Theme.of(context).brightness == Brightness.dark; return Padding( - padding: const EdgeInsets.symmetric(vertical: 8), + padding: EdgeInsets.symmetric(vertical: 8.h), child: Row( children: [ Container( - width: 38, - height: 38, + width: 38.w, + height: 38.h, decoration: BoxDecoration( - color: isDarkMode ? Color(0xFF1A365D) : Colors.blue[50], - borderRadius: BorderRadius.circular(8), + color: isDarkMode + ? const Color(0xFF2A2A2A) + : Theme.of(context).primaryColor.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8.r), ), child: Icon( Icons.place, - size: 18, - color: Color(0xFFE11D48), + size: 18.sp, + color: Theme.of(context).primaryColor, ), ), - const SizedBox(width: 12), + SizedBox(width: 12.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -178,19 +187,19 @@ Widget buildLocationItem( Text( name, style: TextStyle( - fontSize: 13, + fontSize: 13.sp, fontWeight: FontWeight.w500, color: isDarkMode - ? Colors.white.withOpacity(0.9) + ? Colors.white.withValues(alpha: 0.9) : Colors.grey[800], ), overflow: TextOverflow.ellipsis, ), - SizedBox(height: 2), + SizedBox(height: 2.h), Text( description, style: TextStyle( - fontSize: 12, + fontSize: 12.sp, color: isDarkMode ? Colors.grey[400] : Colors.grey[600], ), overflow: TextOverflow.ellipsis, @@ -200,10 +209,13 @@ Widget buildLocationItem( ), IconButton( onPressed: () {}, - icon: Icon(Icons.arrow_forward, color: Colors.grey[400]), + icon: Icon( + Icons.arrow_forward, + color: isDarkMode ? Colors.grey[500] : Colors.grey[400] + ), padding: EdgeInsets.zero, - constraints: BoxConstraints(), - iconSize: 20, + constraints: const BoxConstraints(), + iconSize: 20.sp, ), ], ), diff --git a/lib/modules/agent/views/weather_card.dart b/lib/modules/agent/views/weather_card.dart index 323a4a483..8f422601b 100644 --- a/lib/modules/agent/views/weather_card.dart +++ b/lib/modules/agent/views/weather_card.dart @@ -1,5 +1,6 @@ import 'package:common_utils/common_utils.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; /// 构建天气内容卡片 Widget buildWeatherContent(BuildContext context, String city, @@ -12,31 +13,31 @@ Widget buildWeatherContent(BuildContext context, String city, Text( '查询天气情况:', style: TextStyle( - color: isDarkMode ? Colors.white.withOpacity(0.9) : Colors.black87, - fontSize: 14, + color: isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87, + fontSize: 14.sp, height: 1.4, fontWeight: FontWeight.w400, ), ), - const SizedBox(height: 12), + SizedBox(height: 12.h), Container( - padding: const EdgeInsets.all(16), + padding: EdgeInsets.all(16.w), decoration: BoxDecoration( gradient: isDarkMode - ? LinearGradient( + ? const LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFF1E40AF), Color(0xFF1E3A8A)], ) - : LinearGradient( + : const LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFF60A5FA), Color(0xFF3B82F6)], ), - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(12.r), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(isDarkMode ? 0.3 : 0.1), + color: Colors.black.withValues(alpha: isDarkMode ? 0.3 : 0.1), blurRadius: 8, offset: const Offset(0, 2), ), @@ -64,37 +65,37 @@ Widget buildWeatherContent(BuildContext context, String city, Text( now["dayweather"], style: TextStyle( - fontSize: 14, - color: Colors.white.withOpacity(0.9), + fontSize: 14.sp, + color: Colors.white.withValues(alpha: 0.9), ), ), - SizedBox(height: 8), + SizedBox(height: 8.h), Row( children: [ Text( "${now["daytemp"]}°", - style: const TextStyle( - fontSize: 36, + style: TextStyle( + fontSize: 36.sp, fontWeight: FontWeight.bold, color: Colors.white, ), ), - SizedBox(width: 8), + SizedBox(width: 8.w), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '最高: ${now["daytemp"]}°', style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.9), + fontSize: 12.sp, + color: Colors.white.withValues(alpha: 0.9), ), ), Text( '最低: ${now["nighttemp"]}°', style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.9), + fontSize: 12.sp, + color: Colors.white.withValues(alpha: 0.9), ), ), ], @@ -105,26 +106,26 @@ Widget buildWeatherContent(BuildContext context, String city, ), Icon( getWeatherIcon(now['dayweather']), - size: 48, + size: 48.sp, color: Colors.white, ), ], ), - SizedBox(height: 16), + SizedBox(height: 16.h), Container( height: 1, - color: Colors.white.withOpacity(isDarkMode ? 0.15 : 0.2), + color: Colors.white.withValues(alpha: isDarkMode ? 0.15 : 0.2), ), - SizedBox(height: 16), - const Text( + SizedBox(height: 16.h), + Text( '未来预报', style: TextStyle( - fontSize: 14, + fontSize: 14.sp, fontWeight: FontWeight.w600, color: Colors.white, ), ), - SizedBox(height: 8), + SizedBox(height: 8.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: List.generate( @@ -145,35 +146,8 @@ Widget buildWeatherContent(BuildContext context, String city, }, ), ), - SizedBox(height: 16), - Container( - padding: EdgeInsets.symmetric(vertical: 8, horizontal: 12), - decoration: BoxDecoration( - color: isDarkMode - ? Colors.white.withOpacity(0.15) - : Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(8), - ), - child: const Row( - children: [ - Icon( - Icons.info_outline, - size: 16, - color: Colors.white, - ), - SizedBox(width: 8), - Flexible( - child: Text( - '今日紫外线指数较高,外出请做好防晒', - style: TextStyle( - fontSize: 12, - color: Colors.white, - ), - ), - ), - ], - ), - ), + SizedBox(height: 16.h), + _buildWeatherTip(context, now, isDarkMode), ], ), ), @@ -181,6 +155,125 @@ Widget buildWeatherContent(BuildContext context, String city, ); } +/// 构建智能天气提示 +Widget _buildWeatherTip(BuildContext context, Map now, bool isDarkMode) { + final weatherTip = _generateWeatherTip(now); + + return Container( + padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 12.w), + decoration: BoxDecoration( + color: isDarkMode + ? Colors.white.withValues(alpha: 0.15) + : Colors.white.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(8.r), + ), + child: Row( + children: [ + Icon( + weatherTip.icon, + size: 16.sp, + color: Colors.white, + ), + SizedBox(width: 8.w), + Flexible( + child: Text( + weatherTip.message, + style: TextStyle( + fontSize: 12.sp, + color: Colors.white, + ), + ), + ), + ], + ), + ); +} + +/// 天气提示数据类 +class WeatherTip { + final IconData icon; + final String message; + + const WeatherTip({required this.icon, required this.message}); +} + +/// 根据天气数据生成智能提示 +WeatherTip _generateWeatherTip(Map now) { + final dayWeather = (now['dayweather'] as String? ?? '').trim(); + final dayTemp = int.tryParse(now['daytemp']?.toString() ?? '0') ?? 0; + final nightTemp = int.tryParse(now['nighttemp']?.toString() ?? '0') ?? 0; + + // 高温提示 (>= 35°C) + if (dayTemp >= 35) { + return const WeatherTip( + icon: Icons.local_fire_department, + message: '今日高温炎热,请注意防暑降温,多喝水避免中暑', + ); + } + + // 低温提示 (<= 5°C) + if (dayTemp <= 5) { + return const WeatherTip( + icon: Icons.ac_unit, + message: '今日气温较低,外出请注意保暖,小心感冒', + ); + } + + // 雨天提示 + if (dayWeather.contains('雨') || ['阵雨', '雷阵雨', '小雨', '中雨', '大雨', '暴雨'].any((rain) => dayWeather.contains(rain))) { + return const WeatherTip( + icon: Icons.umbrella, + message: '今日有雨,外出请携带雨具,注意出行安全', + ); + } + + // 雪天提示 + if (dayWeather.contains('雪') || ['阵雪', '小雪', '中雪', '大雪', '暴雪'].any((snow) => dayWeather.contains(snow))) { + return const WeatherTip( + icon: Icons.ac_unit, + message: '今日有雪,路面湿滑请注意安全,做好保暖措施', + ); + } + + // 雾霾提示 + if (dayWeather.contains('雾') || dayWeather.contains('霾') || ['雾', '浓雾', '霾', '中度霾', '重度霾'].any((fog) => dayWeather.contains(fog))) { + return const WeatherTip( + icon: Icons.blur_on, + message: '今日有雾霾,能见度较低,外出请佩戴口罩', + ); + } + + // 大风提示 + if (dayWeather.contains('风') || ['大风', '强风', '疾风', '烈风'].any((wind) => dayWeather.contains(wind))) { + return const WeatherTip( + icon: Icons.air, + message: '今日风力较大,外出请注意安全,固定好物品', + ); + } + + // 晴天紫外线提示 (温度 >= 25°C) + if (['晴', '少云', '晴间多云'].any((sunny) => dayWeather.contains(sunny)) && dayTemp >= 25) { + return const WeatherTip( + icon: Icons.wb_sunny, + message: '今日阳光充足紫外线较强,外出请做好防晒', + ); + } + + // 温差大提示 (>= 10°C) + if ((dayTemp - nightTemp).abs() >= 10) { + return const WeatherTip( + icon: Icons.thermostat, + message: '今日昼夜温差较大,请适时增减衣物', + ); + } + + // 默认舒适天气提示 + return const WeatherTip( + icon: Icons.wb_sunny_outlined, + message: '今日天气适宜,是外出活动的好时光', + ); +} + /// 构建单日天气预报 Widget _buildForecastDay(String day, IconData icon, String temp) { return Column( @@ -188,21 +281,21 @@ Widget _buildForecastDay(String day, IconData icon, String temp) { Text( day, style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.9), + fontSize: 12.sp, + color: Colors.white.withValues(alpha: 0.9), ), ), - SizedBox(height: 4), + SizedBox(height: 4.h), Icon( icon, - size: 20, + size: 20.sp, color: Colors.white, ), - SizedBox(height: 4), + SizedBox(height: 4.h), Text( temp, style: TextStyle( - fontSize: 12, + fontSize: 12.sp, fontWeight: FontWeight.w500, color: Colors.white, ),