diff --git a/lib/core/utils/json_safe.dart b/lib/core/utils/json_safe.dart new file mode 100644 index 00000000..c162bde4 --- /dev/null +++ b/lib/core/utils/json_safe.dart @@ -0,0 +1,32 @@ +class JsonSafe { + static String asString(dynamic value, [String fallback = '']) { + if (value is String) return value; + return fallback; + } + + static String? asStringOrNull(dynamic value) { + if (value is String) return value; + return null; + } + + static int asInt(dynamic value, [int fallback = 0]) { + if (value is int) return value; + if (value is num) return value.toInt(); + if (value is String) return int.tryParse(value) ?? fallback; + return fallback; + } + + static double asDouble(dynamic value, [double fallback = 0.0]) { + if (value is double) return value; + if (value is num) return value.toDouble(); + if (value is String) return double.tryParse(value) ?? fallback; + return fallback; + } + + static bool asBool(dynamic value, [bool fallback = false]) { + if (value is bool) return value; + if (value is int) return value != 0; + if (value is String) return value.toLowerCase() == 'true'; + return fallback; + } +} diff --git a/lib/features/ai/data/models/session.dart b/lib/features/ai/data/models/session.dart index 717f763b..0556a72d 100644 --- a/lib/features/ai/data/models/session.dart +++ b/lib/features/ai/data/models/session.dart @@ -1,3 +1,5 @@ +import 'package:maibu_satabot_v2/core/utils/json_safe.dart'; + class Session { final String sessId; final String title; @@ -6,8 +8,8 @@ class Session { factory Session.fromJson(Map json) { return Session( - sessId: json['sessId'], - title: json['title'], + sessId: JsonSafe.asString(json['sessId']), + title: JsonSafe.asString(json['title']), ); } } diff --git a/lib/features/auth/data/models/user_model.dart b/lib/features/auth/data/models/user_model.dart index d37729bf..9371a677 100644 --- a/lib/features/auth/data/models/user_model.dart +++ b/lib/features/auth/data/models/user_model.dart @@ -1,4 +1,5 @@ import 'package:maibu_satabot_v2/core/data/base_model.dart'; +import 'package:maibu_satabot_v2/core/utils/json_safe.dart'; import '../../../../core/domain/entities/user_entity.dart'; @@ -14,15 +15,14 @@ class UserModel extends UserEntity implements BaseModel { }); factory UserModel.fromJson(Map json) { - print(json); return UserModel( - userId: json['userId'], - username: json['username'], - nickname: json['nickName'], - token: json['token'], - avatar: json['avatar'], - email: json['email'], - phone: json['phone'], + userId: JsonSafe.asString(json['userId']), + username: JsonSafe.asString(json['username']), + nickname: JsonSafe.asString(json['nickName']), + token: JsonSafe.asString(json['token']), + avatar: JsonSafe.asStringOrNull(json['avatar']), + email: JsonSafe.asStringOrNull(json['email']), + phone: JsonSafe.asStringOrNull(json['phone']), ); } diff --git a/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart b/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart index a141c4c0..f074d4d2 100644 --- a/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart +++ b/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart @@ -84,8 +84,20 @@ class DeviceHttpDatasourceImpl implements DeviceHttpDatasource { if (responseData['total'] == 0) { return []; } else { + final rows = responseData['rows']; + debugPrint('🔧 [DeviceAPI] 原始 rows 数量: ${rows.length}'); + if (rows.isNotEmpty) { + debugPrint('🔧 [DeviceAPI] 第一个元素类型: ${rows.first.runtimeType}'); + debugPrint('🔧 [DeviceAPI] 第一个元素内容: ${rows.first}'); + if (rows.first is Map) { + debugPrint('🔧 [DeviceAPI] 第一个元素的 keys: ${rows.first.keys}'); + rows.first.forEach((k, v) { + debugPrint('🔧 [DeviceAPI] $k: ${v.runtimeType} = $v'); + }); + } + } List devices = []; - for (var item in responseData['rows']) { + for (var item in rows) { devices.add(DeviceEntity.fromJson(item)); } return devices; diff --git a/lib/features/devices/data/models/device_model.dart b/lib/features/devices/data/models/device_model.dart index 2579882f..75a45de6 100644 --- a/lib/features/devices/data/models/device_model.dart +++ b/lib/features/devices/data/models/device_model.dart @@ -1,4 +1,5 @@ import 'package:maibu_satabot_v2/core/data/base_model.dart'; +import 'package:maibu_satabot_v2/core/utils/json_safe.dart'; import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.dart'; class DeviceModel extends DeviceEntity implements BaseModel { @@ -17,16 +18,16 @@ class DeviceModel extends DeviceEntity implements BaseModel { factory DeviceModel.fromJson(Map json) { return DeviceModel( - deviceName: json['deviceName'], - productId: json['productId'], - productName: json['productName'], - tenantId: json['tenantId'], - tenantName: json['tenantName'], - status: json['status'], - activeTime: json['activeTime'], - deviceAlias: json['deviceAlias'], - isBind: json['isBind'], - onlineStatus: json['onlineStatus'], + deviceName: JsonSafe.asString(json['deviceName']), + productId: JsonSafe.asInt(json['productId'], -1), + productName: JsonSafe.asString(json['productName'], "割草机产品MC700"), + tenantId: JsonSafe.asInt(json['tenantId']), + tenantName: JsonSafe.asString(json['tenantName']), + status: JsonSafe.asInt(json['status']), + activeTime: JsonSafe.asStringOrNull(json['activeTime']), + deviceAlias: JsonSafe.asStringOrNull(json['deviceAlias']), + isBind: JsonSafe.asInt(json['isBind']), + onlineStatus: JsonSafe.asInt(json['onlineStatus']), ); } diff --git a/lib/features/devices/domain/entities/device_entity.dart b/lib/features/devices/domain/entities/device_entity.dart index 7d160d4a..808a3365 100644 --- a/lib/features/devices/domain/entities/device_entity.dart +++ b/lib/features/devices/domain/entities/device_entity.dart @@ -1,4 +1,5 @@ import 'package:equatable/equatable.dart'; +import '../../../../core/utils/json_safe.dart'; class DeviceEntity extends Equatable { final String deviceName; @@ -25,26 +26,24 @@ class DeviceEntity extends Equatable { this.onlineStatus = 0, }); - // 方便从后端 JSON 转换 factory DeviceEntity.fromJson(Map json) { return DeviceEntity( - deviceName: json['deviceName'], - productId: json['productId'] ?? -1, - productName: json['productName'] ?? "割草机产品MC700", - tenantId: json['tenantId'], - tenantName: json['tenantName'], - status: json['status'] ?? 0, - activeTime: json['activeTime'], - deviceAlias: json['deviceAlias'], - isBind: json['isBind'] ?? 0, - onlineStatus: json['onlineStatus'] ?? 0, + deviceName: JsonSafe.asString(json['deviceName']), + productId: JsonSafe.asInt(json['productId'], -1), + productName: JsonSafe.asString(json['productName'], "割草机产品MC700"), + tenantId: JsonSafe.asInt(json['tenantId']), + tenantName: JsonSafe.asString(json['tenantName']), + status: JsonSafe.asInt(json['status']), + activeTime: JsonSafe.asStringOrNull(json['activeTime']), + deviceAlias: JsonSafe.asStringOrNull(json['deviceAlias']), + isBind: JsonSafe.asInt(json['isBind']), + onlineStatus: JsonSafe.asInt(json['onlineStatus']), ); } - // 获取显示的名称(优先别名,没有则用设备名) String get displayName => (deviceAlias != null && deviceAlias!.isNotEmpty) ? deviceAlias! - : (deviceName ?? "未知设备"); + : (deviceName.isNotEmpty ? deviceName : "未知设备"); // 辅助方法:判断是否在线 bool get isOnline => onlineStatus == 1; diff --git a/lib/features/devices/domain/entities/device_run_hostrity_entity.dart b/lib/features/devices/domain/entities/device_run_hostrity_entity.dart index 9a17af0a..b13d8f96 100644 --- a/lib/features/devices/domain/entities/device_run_hostrity_entity.dart +++ b/lib/features/devices/domain/entities/device_run_hostrity_entity.dart @@ -1,11 +1,12 @@ import 'package:equatable/equatable.dart'; +import '../../../../core/utils/json_safe.dart'; class DeviceRunStatisticsEntity extends Equatable { - final String startTime; // 开始时间 - final String endTime; // 结束时间 - final double workArea; // 工作面积 - final double? distance; // 工作距离(可为空) - final int time; // 花费时间 + final String startTime; + final String endTime; + final double workArea; + final double? distance; + final int time; const DeviceRunStatisticsEntity({ required this.startTime, @@ -17,11 +18,11 @@ class DeviceRunStatisticsEntity extends Equatable { factory DeviceRunStatisticsEntity.fromJson(Map json) { return DeviceRunStatisticsEntity( - startTime: json['startTime'] as String, - endTime: json['endTime'] as String, - workArea: (json['workArea'] as num).toDouble(), - distance: json['distance'] != null ? (json['distance'] as num).toDouble() : null, - time: json['time'] as int, + startTime: JsonSafe.asString(json['startTime']), + endTime: JsonSafe.asString(json['endTime']), + workArea: JsonSafe.asDouble(json['workArea']), + distance: json['distance'] != null ? JsonSafe.asDouble(json['distance']) : null, + time: JsonSafe.asInt(json['time']), ); } diff --git a/lib/features/home/presentation/widgets/map/testmap_pages.dart b/lib/features/home/presentation/widgets/map/testmap_pages.dart index 009efa89..7c84a7ef 100644 --- a/lib/features/home/presentation/widgets/map/testmap_pages.dart +++ b/lib/features/home/presentation/widgets/map/testmap_pages.dart @@ -22,8 +22,10 @@ import 'package:maibu_satabot_v2/core/localization/app_localizations.dart'; import 'package:maibu_satabot_v2/core/network/net_message_dispatcher.dart'; import 'package:maibu_satabot_v2/core/network/protocol_decoder.dart'; import 'package:maibu_satabot_v2/core/router/route_paths.dart'; -import 'package:maibu_satabot_v2/features/devices/data/models/device_add_path_point_model.dart' as work_area_model; -import 'package:maibu_satabot_v2/features/devices/data/models/device_work_area_param_model.dart' as work_area_model; +import 'package:maibu_satabot_v2/features/devices/data/models/device_add_path_point_model.dart' + as work_area_model; +import 'package:maibu_satabot_v2/features/devices/data/models/device_work_area_param_model.dart' + as work_area_model; import 'package:maibu_satabot_v2/features/devices/data/repositories/generate_path_repository_Impl.dart'; import 'package:maibu_satabot_v2/features/devices/domain/usecases/get_work_record_usecase.dart'; import 'package:maibu_satabot_v2/features/devices/domain/usecases/select_work_record_usecase.dart'; @@ -63,7 +65,8 @@ const String kSavedIsWorkPanelOpen = 'saved_is_work_panel_open'; const String kSavedSelectedPlot = 'saved_selected_plot'; const String kSavedStartWorkList = 'saved_start_work_list'; const String kSavedWorkMode = 'saved_work_mode'; -const String kSavedWorkStatus = 'saved_work_status'; // 作业状态(idle/working/paused) +const String kSavedWorkStatus = + 'saved_work_status'; // 作业状态(idle/working/paused) const String kSavedIsStartWork = 'saved_is_start_work'; // 是否开始作业 const String kSavedIsStopWork = 'saved_is_stop_work'; // 是否点击过停止 const String kSavedTPMode = "saved_tp_mode"; @@ -78,7 +81,12 @@ class PlotData { final String imageUrl; // 图片URL(本地/assets/网络都可) final String? jsonData; // 原始数据的JSON字符串(可选,便于调试或后续使用) - PlotData({required this.id, required this.plotName, required this.imageUrl, this.jsonData}); + PlotData({ + required this.id, + required this.plotName, + required this.imageUrl, + this.jsonData, + }); } class PlotDataPath { @@ -149,7 +157,8 @@ class _MapPageEnterpriseState extends State { LatLng _mapCenter = const LatLng(39.9042, 116.4074); double _headingAngle = 0.0; // 当前机器航向角(单位:度) - List typedPathList = []; // 存储生成路径的坐标列表(已转换为LatLng) + List typedPathList = + []; // 存储生成路径的坐标列表(已转换为LatLng) // ========== 障碍物模式核心状态 ========== List> _obstacleHoles = []; // 存储多组障碍物打点(嵌套数组:每组是一个障碍物) @@ -194,7 +203,10 @@ class _MapPageEnterpriseState extends State { WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted && _mapController.camera != null) { final originalCenter = _mapController.camera!.center; - final highPrecisionCenter = LatLng(originalCenter.latitude, originalCenter.longitude); + final highPrecisionCenter = LatLng( + originalCenter.latitude, + originalCenter.longitude, + ); setState(() { _mapCenter = highPrecisionCenter; @@ -216,7 +228,10 @@ class _MapPageEnterpriseState extends State { if (event is MapEventMove || event is MapEventMoveEnd) { if (mounted && _mapController.camera != null) { final originalCenter = _mapController.camera!.center; - final highPrecisionCenter = LatLng(originalCenter.latitude, originalCenter.longitude); + final highPrecisionCenter = LatLng( + originalCenter.latitude, + originalCenter.longitude, + ); setState(() { _mapCenter = highPrecisionCenter; @@ -280,16 +295,24 @@ class _MapPageEnterpriseState extends State { final prefs = await SharedPreferences.getInstance(); final workStatusStr = prefs.getString(kSavedWorkStatus); if (workStatusStr != null) { - _workStatus = WorkStatus.values.firstWhere((e) => e.toString() == workStatusStr, orElse: () => WorkStatus.idle); + _workStatus = WorkStatus.values.firstWhere( + (e) => e.toString() == workStatusStr, + orElse: () => WorkStatus.idle, + ); } final modeStr = prefs.getString(kSavedTPMode); if (modeStr != null) { - _traceManager.setMode(TPMode.values.firstWhere((e) => e.toString() == modeStr)); + _traceManager.setMode( + TPMode.values.firstWhere((e) => e.toString() == modeStr), + ); } final robotModeStr = prefs.getString(kSavedCurrentRobotMode); if (robotModeStr != null) { - _currentRobotMode = RobotMode.values.firstWhere((e) => e.toString() == robotModeStr, orElse: () => RobotMode.point); + _currentRobotMode = RobotMode.values.firstWhere( + (e) => e.toString() == robotModeStr, + orElse: () => RobotMode.point, + ); } // 读取 生成完成的路径 typedPathList @@ -298,7 +321,10 @@ class _MapPageEnterpriseState extends State { final List typedPathJson = jsonDecode(typedPathString); setState(() { typedPathList = typedPathJson.map((p) { - return work_area_model.DeviceAddPathPointModel(latitude: p['lat'], longitude: p['lng']); + return work_area_model.DeviceAddPathPointModel( + latitude: p['lat'], + longitude: p['lng'], + ); }).toList(); }); } @@ -315,21 +341,42 @@ class _MapPageEnterpriseState extends State { final pathJson = prefs.getString(kSavedGcjPathPoints); if (pathJson != null) { final List pathList = jsonDecode(pathJson); - gcjPathPoints = pathList.map((item) => LatLng(double.parse(item['lat'].toString()), double.parse(item['lng'].toString()))).toList(); + gcjPathPoints = pathList + .map( + (item) => LatLng( + double.parse(item['lat'].toString()), + double.parse(item['lng'].toString()), + ), + ) + .toList(); } // 加载外边界点 final outerJson = prefs.getString(kSavedGcjOuterPoints); if (outerJson != null) { final List outerList = jsonDecode(outerJson); - gcjOuterPoints = outerList.map((item) => LatLng(double.parse(item['lat'].toString()), double.parse(item['lng'].toString()))).toList(); + gcjOuterPoints = outerList + .map( + (item) => LatLng( + double.parse(item['lat'].toString()), + double.parse(item['lng'].toString()), + ), + ) + .toList(); } // 加载打点数据 final markedJson = prefs.getString(kSavedMarkedPoints); if (markedJson != null) { final List markedList = jsonDecode(markedJson); - _markedPoints = markedList.map((item) => LatLng(double.parse(item['lat'].toString()), double.parse(item['lng'].toString()))).toList(); + _markedPoints = markedList + .map( + (item) => LatLng( + double.parse(item['lat'].toString()), + double.parse(item['lng'].toString()), + ), + ) + .toList(); } // 加载障碍物数据 @@ -337,7 +384,14 @@ class _MapPageEnterpriseState extends State { if (obstacleJson != null) { final List obstacleList = jsonDecode(obstacleJson); _obstacleHoles = obstacleList.map((hole) { - return (hole as List).map((item) => LatLng(double.parse(item['lat'].toString()), double.parse(item['lng'].toString()))).toList(); + return (hole as List) + .map( + (item) => LatLng( + double.parse(item['lat'].toString()), + double.parse(item['lng'].toString()), + ), + ) + .toList(); }).toList(); } @@ -352,7 +406,10 @@ class _MapPageEnterpriseState extends State { workMode = prefs.getString(kSavedWorkMode) ?? "弓字模式"; // 读取 _currentWorkMode = prefs.getString(kSavedCurrentWorkMode) != null - ? WorkMode.values.firstWhere((e) => e.toString() == prefs.getString(kSavedCurrentWorkMode), orElse: () => WorkMode.bow) + ? WorkMode.values.firstWhere( + (e) => e.toString() == prefs.getString(kSavedCurrentWorkMode), + orElse: () => WorkMode.bow, + ) : WorkMode.bow; // 3. 恢复作业列表 final startWorkJson = prefs.getString(kSavedStartWorkList); @@ -364,11 +421,20 @@ class _MapPageEnterpriseState extends State { final selectedPlotJson = prefs.getString(kSavedSelectedPlot); if (selectedPlotJson != null && selectedPlotJson.isNotEmpty) { final Map plotMap = jsonDecode(selectedPlotJson); + final rawJd = plotMap['jsonData']; + String? jdStr; + if (rawJd == null) { + jdStr = null; + } else if (rawJd is String) { + jdStr = rawJd; + } else { + jdStr = jsonEncode(rawJd); + } _selectedPlot = PlotData( id: plotMap['id'] ?? '', plotName: plotMap['plotName'] ?? '', imageUrl: plotMap['imageUrl'] ?? '', - jsonData: plotMap['jsonData'], + jsonData: jdStr, ); } @@ -406,24 +472,34 @@ class _MapPageEnterpriseState extends State { final prefs = await SharedPreferences.getInstance(); // 保存路径点 - final pathList = gcjPathPoints.map((point) => {'lat': point.latitude, 'lng': point.longitude}).toList(); + final pathList = gcjPathPoints + .map((point) => {'lat': point.latitude, 'lng': point.longitude}) + .toList(); prefs.setString(kSavedGcjPathPoints, jsonEncode(pathList)); // 保存外边界点 - final outerList = gcjOuterPoints.map((point) => {'lat': point.latitude, 'lng': point.longitude}).toList(); + final outerList = gcjOuterPoints + .map((point) => {'lat': point.latitude, 'lng': point.longitude}) + .toList(); prefs.setString(kSavedGcjOuterPoints, jsonEncode(outerList)); // 保存打点数据 - final markedList = _markedPoints.map((point) => {'lat': point.latitude, 'lng': point.longitude}).toList(); + final markedList = _markedPoints + .map((point) => {'lat': point.latitude, 'lng': point.longitude}) + .toList(); prefs.setString(kSavedMarkedPoints, jsonEncode(markedList)); // 保存障碍物数据 final obstacleList = _obstacleHoles.map((hole) { - return hole.map((point) => {'lat': point.latitude, 'lng': point.longitude}).toList(); + return hole + .map((point) => {'lat': point.latitude, 'lng': point.longitude}) + .toList(); }).toList(); prefs.setString(kSavedObstacleHoles, jsonEncode(obstacleList)); - final typedPath = typedPathList.map((point) => {'lat': point.latitude, 'lng': point.longitude}).toList(); + final typedPath = typedPathList + .map((point) => {'lat': point.latitude, 'lng': point.longitude}) + .toList(); prefs.setString("kSavedTypedPathList", jsonEncode(typedPath)); // 保存作业区域完成状态 @@ -515,10 +591,21 @@ class _MapPageEnterpriseState extends State { } bool _isValidLatLng(double lat, double lng) { - return lat != 0 && lng != 0 && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180; + return lat != 0 && + lng != 0 && + lat >= -90 && + lat <= 90 && + lng >= -180 && + lng <= 180; } - void _onDeviceData(double lng, double lat, bool obfFlag, int headingStatus, dynamic controlMode) { + void _onDeviceData( + double lng, + double lat, + bool obfFlag, + int headingStatus, + dynamic controlMode, + ) { try { // 1. 校验坐标是否有效 bool isValid = _isValidLatLng(lat, lng); @@ -617,7 +704,14 @@ class _MapPageEnterpriseState extends State { context: context, barrierDismissible: false, // 禁止点击外部关闭 builder: (ctx) => const Center( - child: SizedBox(width: 60, height: 60, child: CircularProgressIndicator(strokeWidth: 3, color: Colors.white)), + child: SizedBox( + width: 60, + height: 60, + child: CircularProgressIndicator( + strokeWidth: 3, + color: Colors.white, + ), + ), ), ); @@ -631,7 +725,13 @@ class _MapPageEnterpriseState extends State { } else { // 截图失败时,允许空图片保存(可根据业务调整为强制失败) _savePlotData(plotName, null); - _showPageToast(message: loc.translate('route_planning.save_success') + "," + "但地图截图生成失败!", type: ToastType.warn); + _showPageToast( + message: + loc.translate('route_planning.save_success') + + "," + + "但地图截图生成失败!", + type: ToastType.warn, + ); //ToastUtils.showWarn(context, '地块保存成功,但地图截图生成失败!'); //ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('地块保存成功,但地图截图生成失败!'), backgroundColor: Colors.amber)); @@ -670,7 +770,9 @@ class _MapPageEnterpriseState extends State { // 格式化 JSON 打印,更易读 try { dynamic jsonObj = jsonDecode(content); - debugPrint(' 内容 (content): ${const JsonEncoder.withIndent(' ').convert(jsonObj)}'); + debugPrint( + ' 内容 (content): ${const JsonEncoder.withIndent(' ').convert(jsonObj)}', + ); } catch (e) { debugPrint(' 内容 (content): $content'); } @@ -678,7 +780,9 @@ class _MapPageEnterpriseState extends State { } else { // 对于图片文件,打印大小即可,避免打印海量 Base64 file.finalize().first.then((bytes) { - debugPrint(' 文件大小: ${bytes.length} 字节 (约 ${(bytes.length / 1024).toStringAsFixed(1)} KB)'); + debugPrint( + ' 文件大小: ${bytes.length} 字节 (约 ${(bytes.length / 1024).toStringAsFixed(1)} KB)', + ); }); } } @@ -689,7 +793,10 @@ class _MapPageEnterpriseState extends State { // 1. 获取用户ID final userId = context.read().state.user?.userId ?? ""; if (userId.isEmpty) { - _showPageToast(message: loc.translate('route_planning.user_id_empty'), type: ToastType.error); + _showPageToast( + message: loc.translate('route_planning.user_id_empty'), + type: ToastType.error, + ); //ToastUtils.showError(context, '用户ID为空,无法保存!'); return; @@ -703,13 +810,20 @@ class _MapPageEnterpriseState extends State { 'name': plotName, // 地块名称 'outer': // 核心修改:根据机器人模式选择不同的坐标源 - (_currentRobotMode == RobotMode.robot ? _robotModeWgsPoints : gcjOuterPoints).map((point) { - final wgs84 = _currentRobotMode == RobotMode.robot - ? point // Robot模式直接使用原始WGS84坐标 - : gcj02ToWgs84(point.latitude, point.longitude); // Point模式转换 + (_currentRobotMode == RobotMode.robot + ? _robotModeWgsPoints + : gcjOuterPoints) + .map((point) { + final wgs84 = _currentRobotMode == RobotMode.robot + ? point // Robot模式直接使用原始WGS84坐标 + : gcj02ToWgs84( + point.latitude, + point.longitude, + ); // Point模式转换 - return {'lng': wgs84.longitude, 'lat': wgs84.latitude}; - }).toList(), + return {'lng': wgs84.longitude, 'lat': wgs84.latitude}; + }) + .toList(), 'path': _currentWorkMode == WorkMode.custom ? [] // 自定义模式 path 为空数组 : typedPathList @@ -732,7 +846,10 @@ class _MapPageEnterpriseState extends State { 'jsonData': jsonEncode(savePath), // 将 savePath 转为 JSON 字符串 }; final String workRecordJson = jsonEncode(workRecord); - final http.MultipartRequest request = http.MultipartRequest('POST', Uri.parse('https://serviceri.satabot.com/iot/workRecord/add')); + final http.MultipartRequest request = http.MultipartRequest( + 'POST', + Uri.parse('https://serviceri.satabot.com/iot/workRecord/add'), + ); // 5. 处理文件:将 Base64 转为 MultipartFile (对应 JS 的 dataURLtoFile) if (imgBase64 != null && imgBase64.isNotEmpty) { @@ -744,7 +861,14 @@ class _MapPageEnterpriseState extends State { Uint8List bytes = base64Decode(base64String); // 添加文件 (对应 formData.append("file", file)) - request.files.add(http.MultipartFile.fromBytes('file', bytes, filename: 'image.jpg', contentType: http.MediaType('image', 'jpeg'))); + request.files.add( + http.MultipartFile.fromBytes( + 'file', + bytes, + filename: 'image.jpg', + contentType: http.MediaType('image', 'jpeg'), + ), + ); } // 6. 添加 workRecord (对应 formData.append("workRecord", Blob)) @@ -759,7 +883,10 @@ class _MapPageEnterpriseState extends State { // 7. 发送请求 try { - _showPageToast(message: loc.translate('route_planning.saving') + "「$plotName」...", type: ToastType.loading); + _showPageToast( + message: loc.translate('route_planning.saving') + "「$plotName」...", + type: ToastType.loading, + ); //ToastUtils.showLoading(context, '正在保存地块「$plotName」...'); //ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('正在保存地块...'), backgroundColor: Colors.blue)); @@ -768,7 +895,10 @@ class _MapPageEnterpriseState extends State { final String responseBody = await response.stream.bytesToString(); if (response.statusCode == 200) { - _showPageToast(message: loc.translate('route_planning.save_success') + "「$plotName」", type: ToastType.success); + _showPageToast( + message: loc.translate('route_planning.save_success') + "「$plotName」", + type: ToastType.success, + ); //ToastUtils.showSuccess(context, '地块「$plotName」保存成功!'); _clearLocalData(); @@ -790,7 +920,11 @@ class _MapPageEnterpriseState extends State { } } catch (e) { debugPrint('保存失败: $e'); - _showPageToast(message: loc.translate('route_planning.save_failed') + ": ${e.toString()}", type: ToastType.error); + _showPageToast( + message: + loc.translate('route_planning.save_failed') + ": ${e.toString()}", + type: ToastType.error, + ); //ToastUtils.showError(context, '保存失败: ${e.toString()}'); //ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('保存失败: ${e.toString()}'), backgroundColor: Colors.red)); @@ -823,10 +957,16 @@ class _MapPageEnterpriseState extends State { if (_isWorkAreaCompleted && _markedPoints.length >= 3) { _generatePath(showTips: false); } - _showPageToast(message: "已撤回作业区域最后一个点,剩余${_markedPoints.length}个点", type: ToastType.info); + _showPageToast( + message: "已撤回作业区域最后一个点,剩余${_markedPoints.length}个点", + type: ToastType.info, + ); } else { final loc = AppLocalizations.of(context); - _showPageToast(message: loc.translate('route_planning.no_work_points'), type: ToastType.info); + _showPageToast( + message: loc.translate('route_planning.no_work_points'), + type: ToastType.info, + ); } return; } @@ -845,7 +985,10 @@ class _MapPageEnterpriseState extends State { if (_currentObstaclePoints.isEmpty) { _isObstacleEditing = false; } - _showPageToast(message: "已撤回当前空洞最后一个点,剩余${_currentObstaclePoints.length}个点", type: ToastType.info); + _showPageToast( + message: "已撤回当前空洞最后一个点,剩余${_currentObstaclePoints.length}个点", + type: ToastType.info, + ); return; } @@ -856,7 +999,10 @@ class _MapPageEnterpriseState extends State { if (_isWorkAreaCompleted) { _generatePath(showTips: false); } - _showPageToast(message: "已撤回上一个完整空洞,剩余${_obstacleHoles.length}个空洞", type: ToastType.info); + _showPageToast( + message: "已撤回上一个完整空洞,剩余${_obstacleHoles.length}个空洞", + type: ToastType.info, + ); return; } @@ -889,7 +1035,10 @@ class _MapPageEnterpriseState extends State { _saveBoxOpen = false; typedPathList.clear(); final loc = AppLocalizations.of(context); - _showPageToast(message: loc.translate('route_planning.clear_work_area'), type: ToastType.success); + _showPageToast( + message: loc.translate('route_planning.clear_work_area'), + type: ToastType.success, + ); //ToastUtils.showSuccess(context, '已清空所有作业区域点和路径'); //ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('已清空所有作业区域点和路径'))); @@ -898,7 +1047,10 @@ class _MapPageEnterpriseState extends State { else if (_currentAreaMode == AreaMode.obstacle) { if (_obstacleHoles.isEmpty && _currentObstaclePoints.isEmpty) { final loc = AppLocalizations.of(context); - _showPageToast(message: loc.translate('route_planning.no_obstacles'), type: ToastType.info); + _showPageToast( + message: loc.translate('route_planning.no_obstacles'), + type: ToastType.info, + ); //ToastUtils.showInfo(context, '暂无障碍物可删除'); return; @@ -912,7 +1064,10 @@ class _MapPageEnterpriseState extends State { _generatePath(showTips: false); } final loc = AppLocalizations.of(context); - _showPageToast(message: loc.translate('route_planning.clear_obstacles'), type: ToastType.success); + _showPageToast( + message: loc.translate('route_planning.clear_obstacles'), + type: ToastType.success, + ); //ToastUtils.showSuccess(context, '已清空所有障碍物'); } }); @@ -944,7 +1099,8 @@ class _MapPageEnterpriseState extends State { }); try { - if (_currentLatLng != null && _isValidLatLng(_currentLatLng!.latitude, _currentLatLng!.longitude)) { + if (_currentLatLng != null && + _isValidLatLng(_currentLatLng!.latitude, _currentLatLng!.longitude)) { _mapController.move(_currentLatLng!, 18); } @@ -1039,11 +1195,20 @@ class _MapPageEnterpriseState extends State { await _saveDataToLocal(); if (mounted) { - _showPageToast(message: AppLocalizations.of(context).translate('route_planning.clear_cache_success'), type: ToastType.success); + _showPageToast( + message: AppLocalizations.of( + context, + ).translate('route_planning.clear_cache_success'), + type: ToastType.success, + ); } } catch (e) { if (mounted) { - _showPageToast(message: "${AppLocalizations.of(context).translate('route_planning.refresh_failed')}:${e.toString().substring(0, 50)}", type: ToastType.error); + _showPageToast( + message: + "${AppLocalizations.of(context).translate('route_planning.refresh_failed')}:${e.toString().substring(0, 50)}", + type: ToastType.error, + ); } } finally { if (mounted) { @@ -1070,8 +1235,11 @@ class _MapPageEnterpriseState extends State { setState(() { // 保存当前障碍物组(Robot模式下直接用WGS84坐标) - if (_currentRobotMode == RobotMode.robot && _robotModeObsWgsPoints.isNotEmpty) { - final gcjPoints = _robotModeObsWgsPoints.map((wgs) => wgs84ToGcj02(wgs.latitude, wgs.longitude)).toList(); + if (_currentRobotMode == RobotMode.robot && + _robotModeObsWgsPoints.isNotEmpty) { + final gcjPoints = _robotModeObsWgsPoints + .map((wgs) => wgs84ToGcj02(wgs.latitude, wgs.longitude)) + .toList(); _obstacleHoles.add(gcjPoints); _obstacleWgsHoles.add(List.from(_robotModeObsWgsPoints)); } else { @@ -1081,7 +1249,10 @@ class _MapPageEnterpriseState extends State { _isObstacleEditing = false; // 退出编辑状态 }); _saveDataToLocal(); - _showPageToast(message: "已添加第${_obstacleHoles.length}个障碍物区域", type: ToastType.success); + _showPageToast( + message: "已添加第${_obstacleHoles.length}个障碍物区域", + type: ToastType.success, + ); //ToastUtils.showSuccess(context, '已添加第${_obstacleHoles.length}个障碍物区域'); } @@ -1097,7 +1268,9 @@ class _MapPageEnterpriseState extends State { if (_currentRobotMode == RobotMode.point) { if (_currentAreaMode == AreaMode.work) { _markedPoints.add(_mapCenter); - debugPrint('新增作业区域打点:第${_markedPoints.length}个点,经纬度:${_mapCenter.latitude}, ${_mapCenter.longitude}'); + debugPrint( + '新增作业区域打点:第${_markedPoints.length}个点,经纬度:${_mapCenter.latitude}, ${_mapCenter.longitude}', + ); } else { if (_markedPoints.isEmpty) { _showPageToast(message: "请先完成作业区域打点!", type: ToastType.info); @@ -1106,10 +1279,16 @@ class _MapPageEnterpriseState extends State { // 障碍物模式:添加到当前障碍物打点 _currentObstaclePoints.add(_mapCenter); _isObstacleEditing = true; // 标记进入障碍物编辑状态 - debugPrint('新增障碍物打点:第${_currentObstaclePoints.length}个点,经纬度:${_mapCenter.latitude}, ${_mapCenter.longitude}'); + debugPrint( + '新增障碍物打点:第${_currentObstaclePoints.length}个点,经纬度:${_mapCenter.latitude}, ${_mapCenter.longitude}', + ); } } else { - if (_currentLatLng == null || !_isValidLatLng(_currentLatLng!.latitude, _currentLatLng!.longitude)) { + if (_currentLatLng == null || + !_isValidLatLng( + _currentLatLng!.latitude, + _currentLatLng!.longitude, + )) { _showPageToast(message: "设备坐标无效,无法添加打点!", type: ToastType.error); //ToastUtils.showError(context, '设备坐标无效,无法添加打点!'); return; @@ -1119,7 +1298,9 @@ class _MapPageEnterpriseState extends State { if (_currentAreaMode == AreaMode.work) { _markedPoints.add(_currentLatLng!); // 从设备实时坐标取最后一个值 _robotModeWgsPoints.add(_currentWgsLatLng!); - debugPrint('Robot模式新增作业打点:第${_markedPoints.length}个点,经纬度:${_currentLatLng!.latitude}, ${_currentLatLng!.longitude}'); + debugPrint( + 'Robot模式新增作业打点:第${_markedPoints.length}个点,经纬度:${_currentLatLng!.latitude}, ${_currentLatLng!.longitude}', + ); } else { if (_markedPoints.isEmpty || _robotModeWgsPoints.isEmpty) { _showPageToast(message: "请先完成作业区域打点!", type: ToastType.info); @@ -1129,12 +1310,16 @@ class _MapPageEnterpriseState extends State { _currentObstaclePoints.add(_currentLatLng!); _robotModeObsWgsPoints.add(_currentWgsLatLng!); _isObstacleEditing = true; - debugPrint('Robot模式新增障碍物打点:第${_currentObstaclePoints.length}个点,经纬度:${_currentLatLng!.latitude}, ${_currentLatLng!.longitude}'); + debugPrint( + 'Robot模式新增障碍物打点:第${_currentObstaclePoints.length}个点,经纬度:${_currentLatLng!.latitude}, ${_currentLatLng!.longitude}', + ); } } }); _saveDataToLocal(); - debugPrint('$_markedPoints,新增打点:第${_markedPoints.length}个点,经纬度:${_mapCenter.latitude.toStringAsFixed(20)}, ${_mapCenter.longitude.toStringAsFixed(20)}'); + debugPrint( + '$_markedPoints,新增打点:第${_markedPoints.length}个点,经纬度:${_mapCenter.latitude.toStringAsFixed(20)}, ${_mapCenter.longitude.toStringAsFixed(20)}', + ); } // ========== 新增:返回上一级页面的方法 ========== @@ -1167,7 +1352,10 @@ class _MapPageEnterpriseState extends State { // 拖拽区域(整个弹窗可拖拽) onPanUpdate: (details) { setState(() { - _videoPopupPos = Offset(_videoPopupPos.dx + details.delta.dx, _videoPopupPos.dy + details.delta.dy); + _videoPopupPos = Offset( + _videoPopupPos.dx + details.delta.dx, + _videoPopupPos.dy + details.delta.dy, + ); }); }, child: WebRTCMapPlayer( @@ -1218,7 +1406,10 @@ class _MapPageEnterpriseState extends State { return; } - final pathRecords = _loadedPlot.where((item) => item is Map).cast>().toList(); + final pathRecords = _loadedPlot + .where((item) => item is Map) + .cast>() + .toList(); if (pathRecords.isEmpty) { setState(() { _isWorkPanelOpen = true; @@ -1251,8 +1442,12 @@ class _MapPageEnterpriseState extends State { return; } - workMode = parsedJson['planModel'] == WorkMode.bow.value ? "弓字模式" : "自定义模式"; - _currentWorkMode = parsedJson['planModel'] == WorkMode.bow.value ? WorkMode.bow : WorkMode.custom; + workMode = parsedJson['planModel'] == WorkMode.bow.value + ? "弓字模式" + : "自定义模式"; + _currentWorkMode = parsedJson['planModel'] == WorkMode.bow.value + ? WorkMode.bow + : WorkMode.custom; // 【优化4】统一 path/outer 解析逻辑,不重复代码 List pathList = []; @@ -1301,7 +1496,9 @@ class _MapPageEnterpriseState extends State { // 【优化6】整个方法只调用一次 setState,性能暴涨 setState(() { - gcjPathPoints = _currentWorkMode == WorkMode.custom ? [] : newPathPoints; + gcjPathPoints = _currentWorkMode == WorkMode.custom + ? [] + : newPathPoints; gcjOuterPoints = newOuterPoints; _isWorkPanelOpen = true; _isPanelOpen = false; @@ -1335,7 +1532,9 @@ class _MapPageEnterpriseState extends State { color: Colors.white, borderRadius: BorderRadius.circular(8), border: Border.all( - color: _selectedPlot?.id == plot.id ? Colors.blue : Colors.grey[100]!, + color: _selectedPlot?.id == plot.id + ? Colors.blue + : Colors.grey[100]!, width: _selectedPlot?.id == plot.id ? 2 : 1, // 选中项高亮边框 ), ), @@ -1372,7 +1571,11 @@ class _MapPageEnterpriseState extends State { IconButton( onPressed: () => _showDeleteConfirmDialog(plot, onDelete), - icon: const Icon(Icons.delete_outline, color: Colors.redAccent, size: 20), + icon: const Icon( + Icons.delete_outline, + color: Colors.redAccent, + size: 20, + ), padding: EdgeInsets.zero, constraints: const BoxConstraints(), ), @@ -1386,7 +1589,13 @@ class _MapPageEnterpriseState extends State { return const LatLng(30.279651, 120.154871); } - Widget _buildMap(double lat, double lng, bool obfFlag, int headingStatus, String controlMode) { + Widget _buildMap( + double lat, + double lng, + bool obfFlag, + int headingStatus, + String controlMode, + ) { _onDeviceData(lng, lat, obfFlag, headingStatus, controlMode); final gcjPoint = wgs84ToGcj02(lat, lng); @@ -1416,7 +1625,9 @@ class _MapPageEnterpriseState extends State { return FlutterMap( mapController: _mapController, options: MapOptions( - initialCenter: __isValidLatLng(_currentLatLng) ? _currentLatLng! : initCenter, + initialCenter: __isValidLatLng(_currentLatLng) + ? _currentLatLng! + : initCenter, initialZoom: 18, maxZoom: 22, minZoom: 3, @@ -1492,17 +1703,27 @@ class _MapPageEnterpriseState extends State { PolylineLayer( polylines: [ for (int i = 0; i < _markedPoints.length - 1; i++) - Polyline(points: [_markedPoints[i], _markedPoints[i + 1]], color: Colors.orange.withOpacity(0.5), strokeWidth: 1.5), + Polyline( + points: [_markedPoints[i], _markedPoints[i + 1]], + color: Colors.orange.withOpacity(0.5), + strokeWidth: 1.5, + ), ], ), - if (_markedPoints.isNotEmpty && !_isWorkAreaCompleted && _currentRobotMode == RobotMode.point) + if (_markedPoints.isNotEmpty && + !_isWorkAreaCompleted && + _currentRobotMode == RobotMode.point) Stack( // 核心:替换Column为Stack children: [ // 1. 蓝色连线 PolylineLayer( polylines: [ - Polyline(points: [_mapCenter, _markedPoints.last], color: Colors.blue.withOpacity(0.5), strokeWidth: 1.5), + Polyline( + points: [_mapCenter, _markedPoints.last], + color: Colors.blue.withOpacity(0.5), + strokeWidth: 1.5, + ), ], ), // 2. 距离文本Marker @@ -1513,10 +1734,20 @@ class _MapPageEnterpriseState extends State { width: 100, height: 30, child: Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), child: Text( - _calculateLatLngDistance(_mapCenter, _markedPoints.last), - style: const TextStyle(color: Colors.red, fontSize: 12, fontWeight: FontWeight.bold), + _calculateLatLngDistance( + _mapCenter, + _markedPoints.last, + ), + style: const TextStyle( + color: Colors.red, + fontSize: 12, + fontWeight: FontWeight.bold, + ), textAlign: TextAlign.center, ), ), @@ -1526,7 +1757,10 @@ class _MapPageEnterpriseState extends State { ], ), - if (_currentWorkMode == WorkMode.bow && _markedPoints.isNotEmpty && !_isWorkAreaCompleted && _currentRobotMode == RobotMode.point) + if (_currentWorkMode == WorkMode.bow && + _markedPoints.isNotEmpty && + !_isWorkAreaCompleted && + _currentRobotMode == RobotMode.point) PolygonLayer( polygons: [ Polygon( @@ -1559,14 +1793,22 @@ class _MapPageEnterpriseState extends State { // 已绘制的障碍物点连线 for (int i = 0; i < _currentObstaclePoints.length - 1; i++) Polyline( - points: [_currentObstaclePoints[i], _currentObstaclePoints[i + 1]], + points: [ + _currentObstaclePoints[i], + _currentObstaclePoints[i + 1], + ], color: Colors.red.withOpacity(0.8), strokeWidth: 1.5, isDotted: true, // 虚线区分作业区域 ), if (_currentRobotMode == RobotMode.point) // 最后一个点到地图中心的连线 - Polyline(points: [_mapCenter, _currentObstaclePoints.last], color: Colors.red.withOpacity(0.5), strokeWidth: 1.5, isDotted: true), + Polyline( + points: [_mapCenter, _currentObstaclePoints.last], + color: Colors.red.withOpacity(0.5), + strokeWidth: 1.5, + isDotted: true, + ), ], ), @@ -1575,8 +1817,16 @@ class _MapPageEnterpriseState extends State { MarkerLayer( markers: [ // 已完成的障碍物打点 - for (var holeIndex = 0; holeIndex < _obstacleHoles.length; holeIndex++) - for (var pointIndex = 0; pointIndex < _obstacleHoles[holeIndex].length; pointIndex++) + for ( + var holeIndex = 0; + holeIndex < _obstacleHoles.length; + holeIndex++ + ) + for ( + var pointIndex = 0; + pointIndex < _obstacleHoles[holeIndex].length; + pointIndex++ + ) Marker( point: _obstacleHoles[holeIndex][pointIndex], width: 80, @@ -1591,12 +1841,18 @@ class _MapPageEnterpriseState extends State { decoration: const BoxDecoration( color: Colors.red, // 红色标记区分作业区域 shape: BoxShape.circle, - boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 2)], + boxShadow: [ + BoxShadow(color: Colors.black12, blurRadius: 2), + ], ), child: Center( child: Text( '${holeIndex + 1}-${pointIndex + 1}', // 格式:组号-点号 - style: const TextStyle(color: Colors.white, fontSize: 8, fontWeight: FontWeight.bold), + style: const TextStyle( + color: Colors.white, + fontSize: 8, + fontWeight: FontWeight.bold, + ), ), ), ), @@ -1604,7 +1860,11 @@ class _MapPageEnterpriseState extends State { ), ), // 正在绘制的障碍物打点 - for (var pointIndex = 0; pointIndex < _currentObstaclePoints.length; pointIndex++) + for ( + var pointIndex = 0; + pointIndex < _currentObstaclePoints.length; + pointIndex++ + ) Marker( point: _currentObstaclePoints[pointIndex], width: 80, @@ -1619,12 +1879,18 @@ class _MapPageEnterpriseState extends State { decoration: const BoxDecoration( color: Colors.orange, // 橙色标记区分正在绘制 shape: BoxShape.circle, - boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 2)], + boxShadow: [ + BoxShadow(color: Colors.black12, blurRadius: 2), + ], ), child: Center( child: Text( '${pointIndex + 1}', - style: const TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold), + style: const TextStyle( + color: Colors.white, + fontSize: 10, + fontWeight: FontWeight.bold, + ), ), ), ), @@ -1638,7 +1904,13 @@ class _MapPageEnterpriseState extends State { if (gctracePoint != null && gctracePoint!.length >= 2) PolylineLayer( key: const ValueKey('trace_polyline'), - polylines: [Polyline(points: gctracePoint!, color: const Color.fromARGB(255, 6, 187, 232), strokeWidth: 3)], + polylines: [ + Polyline( + points: gctracePoint!, + color: const Color.fromARGB(255, 6, 187, 232), + strokeWidth: 3, + ), + ], ), /// 当前定位 Marker @@ -1679,12 +1951,18 @@ class _MapPageEnterpriseState extends State { decoration: const BoxDecoration( color: Color.fromARGB(255, 10, 218, 55), // 绿色主题色 shape: BoxShape.circle, - boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 2)], + boxShadow: [ + BoxShadow(color: Colors.black12, blurRadius: 2), + ], ), child: Center( child: Text( '$index', - style: const TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold), + style: const TextStyle( + color: Colors.white, + fontSize: 10, + fontWeight: FontWeight.bold, + ), ), ), ), @@ -1729,11 +2007,17 @@ class _MapPageEnterpriseState extends State { await Future.delayed(const Duration(milliseconds: 100)); debugPrint('⚙️ 开始类型转换...'); - final List typedList = startWorkList.whereType>().map((item) { - return work_area_model.DeviceAddPathPointModel(latitude: (item['lat'] as num).toDouble(), longitude: (item['lon'] ?? item["lng"] as num).toDouble()); - }).toList(); + final List typedList = + startWorkList.whereType>().map((item) { + return work_area_model.DeviceAddPathPointModel( + latitude: (item['lat'] as num).toDouble(), + longitude: (item['lon'] ?? item["lng"] as num).toDouble(), + ); + }).toList(); - final Queue pathQueue = Queue.from(typedList); + final Queue pathQueue = Queue.from( + typedList, + ); // 步骤 3:调用 Cubit 方法(类型匹配) await context.read().startRoutePlanning(pathQueue); @@ -1830,7 +2114,13 @@ class _MapPageEnterpriseState extends State { decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(16)), - boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 10, offset: Offset(0, -2))], + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 10, + offset: Offset(0, -2), + ), + ], ), child: Column( mainAxisSize: MainAxisSize.min, @@ -1851,7 +2141,11 @@ class _MapPageEnterpriseState extends State { width: 80, height: 80, color: Colors.grey[200], - child: const Icon(Icons.image_outlined, color: Colors.grey, size: 32), + child: const Icon( + Icons.image_outlined, + color: Colors.grey, + size: 32, + ), ); }, ), @@ -1863,12 +2157,22 @@ class _MapPageEnterpriseState extends State { children: [ Text( _selectedPlot!.plotName, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87), + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), maxLines: 2, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), - Text('${AppLocalizations.of(context).translate('route_planning.work_mode')}:$workMode', style: const TextStyle(fontSize: 14, color: Colors.grey)), + Text( + '${AppLocalizations.of(context).translate('route_planning.work_mode')}:$workMode', + style: const TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), ], ), ), @@ -1889,9 +2193,16 @@ class _MapPageEnterpriseState extends State { //if (isStopWork || !isStartWork) return; }, - icon: const Icon(Icons.close, color: Colors.grey, size: 20), + icon: const Icon( + Icons.close, + color: Colors.grey, + size: 20, + ), padding: EdgeInsets.zero, - constraints: const BoxConstraints(minWidth: 24, minHeight: 24), + constraints: const BoxConstraints( + minWidth: 24, + minHeight: 24, + ), ), ], ), @@ -1908,7 +2219,10 @@ class _MapPageEnterpriseState extends State { Expanded( flex: 1, child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), margin: const EdgeInsets.only(right: 6, bottom: 12), decoration: BoxDecoration( color: Colors.red[50], @@ -1918,12 +2232,19 @@ class _MapPageEnterpriseState extends State { child: const Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Icon(Icons.error_outline, color: Colors.redAccent, size: 16), + Icon( + Icons.error_outline, + color: Colors.redAccent, + size: 16, + ), SizedBox(width: 8), Expanded( child: Text( "路径区域为空", - style: TextStyle(fontSize: 14, color: Colors.redAccent), + style: TextStyle( + fontSize: 14, + color: Colors.redAccent, + ), softWrap: true, maxLines: 2, overflow: TextOverflow.ellipsis, @@ -1939,7 +2260,10 @@ class _MapPageEnterpriseState extends State { Expanded( flex: 1, child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), margin: const EdgeInsets.only(left: 6, bottom: 12), decoration: BoxDecoration( color: Colors.red[50], @@ -1949,12 +2273,19 @@ class _MapPageEnterpriseState extends State { child: const Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Icon(Icons.error_outline, color: Colors.redAccent, size: 16), + Icon( + Icons.error_outline, + color: Colors.redAccent, + size: 16, + ), SizedBox(width: 8), Expanded( child: Text( "航向信息异常", - style: TextStyle(fontSize: 14, color: Colors.redAccent), + style: TextStyle( + fontSize: 14, + color: Colors.redAccent, + ), softWrap: true, maxLines: 2, overflow: TextOverflow.ellipsis, @@ -1974,7 +2305,10 @@ class _MapPageEnterpriseState extends State { width: double.infinity, height: 50, child: ElevatedButton( - onPressed: state.isLoading || startWorkList.isEmpty || headingStatus == 0 + onPressed: + state.isLoading || + startWorkList.isEmpty || + headingStatus == 0 ? null : () { _startWork(); @@ -1982,14 +2316,31 @@ class _MapPageEnterpriseState extends State { style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF00C853), foregroundColor: Colors.white, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), elevation: 2, disabledBackgroundColor: Colors.grey[300], disabledForegroundColor: Colors.grey[600], ), child: state.isLoading - ? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) - : Text(AppLocalizations.of(context).translate('route_planning.start_work'), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ) + : Text( + AppLocalizations.of( + context, + ).translate('route_planning.start_work'), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), ), ) : Row( @@ -2000,18 +2351,28 @@ class _MapPageEnterpriseState extends State { width: 50, height: 50, child: ElevatedButton( - onPressed: () => _workStatus == WorkStatus.working ? _pauseWork() : _resumeWork(), + onPressed: () => + _workStatus == WorkStatus.working + ? _pauseWork() + : _resumeWork(), style: ElevatedButton.styleFrom( - backgroundColor: _workStatus == WorkStatus.working ? Colors.amber : const Color(0xFF00C853), + backgroundColor: + _workStatus == WorkStatus.working + ? Colors.amber + : const Color(0xFF00C853), foregroundColor: Colors.white, shape: const CircleBorder(), elevation: 2, // 调整内边距,让图标居中更协调 - padding: const EdgeInsets.symmetric(horizontal: 8), + padding: const EdgeInsets.symmetric( + horizontal: 8, + ), ), child: Icon( // 作业中显示暂停图标,暂停中显示播放(继续)图标 - _workStatus == WorkStatus.working ? Icons.pause : Icons.play_arrow, + _workStatus == WorkStatus.working + ? Icons.pause + : Icons.play_arrow, size: 24, // 图标尺寸 ), ), @@ -2030,7 +2391,9 @@ class _MapPageEnterpriseState extends State { foregroundColor: Colors.white, shape: const CircleBorder(), elevation: 2, - padding: const EdgeInsets.symmetric(horizontal: 8), + padding: const EdgeInsets.symmetric( + horizontal: 8, + ), ), child: const Icon( Icons.stop, // 停止图标(也可以用 Icons.close) @@ -2075,7 +2438,9 @@ class _MapPageEnterpriseState extends State { Future _captureMapToJpgBase64({int quality = 80}) async { try { // 1. 第一步:截取 PNG (Flutter 唯一支持的格式) - RenderRepaintBoundary? boundary = _mapRepaintKey.currentContext?.findRenderObject() as RenderRepaintBoundary?; + RenderRepaintBoundary? boundary = + _mapRepaintKey.currentContext?.findRenderObject() + as RenderRepaintBoundary?; if (boundary == null) { debugPrint('截图失败:渲染对象未找到'); return null; @@ -2083,7 +2448,9 @@ class _MapPageEnterpriseState extends State { // 🔥 注意:这里是 dart:ui 的 Image,需显式指定 ui.Image ui.Image image = await boundary.toImage(pixelRatio: 2.0); - ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png); + ByteData? byteData = await image.toByteData( + format: ui.ImageByteFormat.png, + ); if (byteData == null) { debugPrint('截图失败:字节数据为空'); return null; @@ -2113,13 +2480,26 @@ class _MapPageEnterpriseState extends State { } // 🔥 改动4:新增方法 - 将Bloc的workRecords转换为PlotData列表 - List _convertWorkRecordsToPlotData(List> records) { + List _convertWorkRecordsToPlotData( + List> records, + ) { return records.map((record) { + final rawJsonData = record['jsonData']; + String? jsonDataStr; + if (rawJsonData == null) { + jsonDataStr = null; + } else if (rawJsonData is String) { + jsonDataStr = rawJsonData; + } else { + jsonDataStr = jsonEncode(rawJsonData); + } return PlotData( - id: record['id']?.toString() ?? DateTime.now().microsecondsSinceEpoch.toString(), // 唯一ID - plotName: record['workName'] ?? '未命名地块', // 地块名称(从接口字段取) - imageUrl: record['imgUrl'] ?? '', // 图片URL(从接口字段取,无则为空) - jsonData: record['jsonData'], // 原始数据的JSON字符串(可选,便于调试或后续使用) + id: + record['id']?.toString() ?? + DateTime.now().microsecondsSinceEpoch.toString(), + plotName: record['workName'] ?? '未命名地块', + imageUrl: record['imgUrl'] ?? '', + jsonData: jsonDataStr, ); }).toList(); } @@ -2158,11 +2538,16 @@ class _MapPageEnterpriseState extends State { try { LatLng firstPointWgs; - if (_currentRobotMode == RobotMode.robot && _robotModeWgsPoints.isNotEmpty) { + if (_currentRobotMode == RobotMode.robot && + _robotModeWgsPoints.isNotEmpty) { firstPointWgs = _robotModeWgsPoints.first; - } else if (_currentRobotMode == RobotMode.point && _markedPoints.isNotEmpty) { + } else if (_currentRobotMode == RobotMode.point && + _markedPoints.isNotEmpty) { LatLng firstPointGcj = _markedPoints.first; - firstPointWgs = gcj02ToWgs84(firstPointGcj.latitude, firstPointGcj.longitude); + firstPointWgs = gcj02ToWgs84( + firstPointGcj.latitude, + firstPointGcj.longitude, + ); } else { if (showTips) { _showPageToast(message: '参考点坐标为空,请先添加作业区域打点!', type: ToastType.error); @@ -2170,18 +2555,29 @@ class _MapPageEnterpriseState extends State { return; } - final referencePoint = work_area_model.ReferencePoint(lat: firstPointWgs.latitude, lon: firstPointWgs.longitude); + final referencePoint = work_area_model.ReferencePoint( + lat: firstPointWgs.latitude, + lon: firstPointWgs.longitude, + ); final heading = _angle == -1 ? -1 : _angle.toInt(); List outerPositions = []; - if (_currentRobotMode == RobotMode.robot && _robotModeWgsPoints.isNotEmpty) { + if (_currentRobotMode == RobotMode.robot && + _robotModeWgsPoints.isNotEmpty) { outerPositions = _robotModeWgsPoints.map((latLng) { - return work_area_model.Position(lat: latLng.latitude, lon: latLng.longitude); + return work_area_model.Position( + lat: latLng.latitude, + lon: latLng.longitude, + ); }).toList(); - } else if (_currentRobotMode == RobotMode.point && _markedPoints.isNotEmpty) { + } else if (_currentRobotMode == RobotMode.point && + _markedPoints.isNotEmpty) { outerPositions = _markedPoints.map((latLng) { final wgs84Point = gcj02ToWgs84(latLng.latitude, latLng.longitude); - return work_area_model.Position(lat: wgs84Point.latitude, lon: wgs84Point.longitude); + return work_area_model.Position( + lat: wgs84Point.latitude, + lon: wgs84Point.longitude, + ); }).toList(); } gcjOuterPoints = outerPositions.map((point) { @@ -2191,32 +2587,49 @@ class _MapPageEnterpriseState extends State { return LatLng(gcjPoint.latitude, gcjPoint.longitude); }).toList(); - final outerBoundary = work_area_model.OuterBoundary(position: outerPositions, sideWidth: _workDistance); + final outerBoundary = work_area_model.OuterBoundary( + position: outerPositions, + sideWidth: _workDistance, + ); work_area_model.HoleBoundary? holeBoundary; if (_obstacleHoles.isNotEmpty) { List> positionList = []; - if (_currentRobotMode == RobotMode.robot && _robotModeObsWgsPoints.isNotEmpty) { + if (_currentRobotMode == RobotMode.robot && + _robotModeObsWgsPoints.isNotEmpty) { for (var holePoints in _obstacleWgsHoles) { List innerPositionList = []; innerPositionList = holePoints.map((latLng) { - return work_area_model.Position(lat: latLng.latitude, lon: latLng.longitude); + return work_area_model.Position( + lat: latLng.latitude, + lon: latLng.longitude, + ); }).toList(); positionList.add(innerPositionList); } - } else if (_currentRobotMode == RobotMode.point && _obstacleHoles.isNotEmpty) { + } else if (_currentRobotMode == RobotMode.point && + _obstacleHoles.isNotEmpty) { for (var holePoints in _obstacleHoles) { List innerPositionList = []; innerPositionList = holePoints.map((latLng) { - final wgs84Point = gcj02ToWgs84(latLng.latitude, latLng.longitude); - return work_area_model.Position(lat: wgs84Point.latitude, lon: wgs84Point.longitude); + final wgs84Point = gcj02ToWgs84( + latLng.latitude, + latLng.longitude, + ); + return work_area_model.Position( + lat: wgs84Point.latitude, + lon: wgs84Point.longitude, + ); }).toList(); positionList.add(innerPositionList); } } - holeBoundary = work_area_model.HoleBoundary(position: positionList, sideWidth: 0.0); + holeBoundary = work_area_model.HoleBoundary( + position: positionList, + sideWidth: 0.0, + ); } Map holes = {}; @@ -2237,7 +2650,10 @@ class _MapPageEnterpriseState extends State { if (cubitState.errorMessage != null) { if (showTips) { - _showPageToast(message: '路径生成失败:${cubitState.errorMessage}', type: ToastType.error); + _showPageToast( + message: '路径生成失败:${cubitState.errorMessage}', + type: ToastType.error, + ); } } else if (cubitState.generatedPath != null) { if (showTips) { @@ -2250,7 +2666,9 @@ class _MapPageEnterpriseState extends State { _currentObstaclePoints.clear(); _robotModeObsWgsPoints.clear(); final pathList = cubitState.generatedPath as List; - typedPathList = pathList.whereType().toList(); + typedPathList = pathList + .whereType() + .toList(); gcjPathPoints = typedPathList.map((point) { double wgs84Lat = point.latitude; double wgs84Lon = point.longitude; @@ -2265,7 +2683,10 @@ class _MapPageEnterpriseState extends State { } catch (e) { debugPrint('路径生成异常:$e'); if (showTips) { - _showPageToast(message: '路径生成异常:${e.toString().substring(0, 50)}', type: ToastType.error); + _showPageToast( + message: '路径生成异常:${e.toString().substring(0, 50)}', + type: ToastType.error, + ); } } } @@ -2293,8 +2714,14 @@ class _MapPageEnterpriseState extends State { child: Container( margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 30), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), - decoration: BoxDecoration(color: _getToastColor(type), borderRadius: BorderRadius.circular(8)), - child: Text(message, style: const TextStyle(color: Colors.white, fontSize: 14)), + decoration: BoxDecoration( + color: _getToastColor(type), + borderRadius: BorderRadius.circular(8), + ), + child: Text( + message, + style: const TextStyle(color: Colors.white, fontSize: 14), + ), ), ), ), @@ -2332,10 +2759,17 @@ class _MapPageEnterpriseState extends State { final menuHeight = 16 * 6; // 假设 VerticalFloatMenu 有 6 个选项,每个高度为 56 final maxTop = screenHeight - menuHeight; final userState = context.watch().state; - final deviceId = context.watch().state.selectedDevice?.deviceName; + final deviceId = context + .watch() + .state + .selectedDevice + ?.deviceName; - if (deviceId != null && userState.user != null && userState.user!.token != null) { - _videoStreamUrl = "webrtc://${TCPConsts.TCP_IP}/live/livestream/$deviceId?token=${userState.user!.token}"; + if (deviceId != null && + userState.user != null && + userState.user!.token != null) { + _videoStreamUrl = + "webrtc://${TCPConsts.TCP_IP}/live/livestream/$deviceId?token=${userState.user!.token}"; } else { _videoStreamUrl = ''; } @@ -2348,7 +2782,9 @@ class _MapPageEnterpriseState extends State { LatLng? targetLatLng; if (arriLatitude != null && arriLongitude != null) { targetLatLng = LatLng(arriLatitude, arriLongitude); - _logger.log("当前轨迹模式: ${_traceManager.getMode()},收到完成点坐标: $targetLatLng"); + _logger.log( + "当前轨迹模式: ${_traceManager.getMode()},收到完成点坐标: $targetLatLng", + ); if (__isValidLatLng(targetLatLng)) { //debugPrint("${targetLatLng}收到完成点arriLatitude"); //if (!isreceiveFirstCompletePoint && isStartWork && _workStatus == WorkStatus.working) { @@ -2423,7 +2859,16 @@ class _MapPageEnterpriseState extends State { body: SafeArea( child: Stack( children: [ - RepaintBoundary(key: _mapRepaintKey, child: _buildMap(currentLat, currentLng, obfFlag, headingStatus, controlMode)), + RepaintBoundary( + key: _mapRepaintKey, + child: _buildMap( + currentLat, + currentLng, + obfFlag, + headingStatus, + controlMode, + ), + ), // 地图核心组件 if (_isRefreshing) @@ -2433,7 +2878,12 @@ class _MapPageEnterpriseState extends State { child: const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, - children: [CircularProgressIndicator(color: Colors.white, strokeWidth: 3)], + children: [ + CircularProgressIndicator( + color: Colors.white, + strokeWidth: 3, + ), + ], ), ), ), @@ -2453,7 +2903,13 @@ class _MapPageEnterpriseState extends State { decoration: BoxDecoration( color: Colors.white.withOpacity(0.8), borderRadius: BorderRadius.circular(20), - boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 3, offset: const Offset(0, 2))], + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 3, + offset: const Offset(0, 2), + ), + ], ), // 核心:用 Stack 实现点击高亮层 + 图标层 child: Stack( @@ -2469,7 +2925,11 @@ class _MapPageEnterpriseState extends State { ), ), // 2. 图标层(绝对居中) - const Icon(Icons.arrow_back_ios, color: Colors.black87, size: 20), + const Icon( + Icons.arrow_back_ios, + color: Colors.black87, + size: 20, + ), ], ), ), @@ -2506,13 +2966,23 @@ class _MapPageEnterpriseState extends State { decoration: BoxDecoration( color: const Color(0xFF00C853), shape: BoxShape.circle, - boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 4, offset: const Offset(0, 2))], + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], ), child: IconButton( onPressed: () { _showSavePlotDialog(); }, - icon: const Icon(Icons.save, color: Colors.white, size: 18), + icon: const Icon( + Icons.save, + color: Colors.white, + size: 18, + ), padding: EdgeInsets.zero, constraints: const BoxConstraints(), ), @@ -2535,7 +3005,9 @@ class _MapPageEnterpriseState extends State { }, onListBox: (bool isOpen) { // 🔥 改动5:加载作业记录(原有逻辑保留) - final userId = context.read().state.user?.userId ?? ""; + final userId = + context.read().state.user?.userId ?? + ""; print('加载作业记录,当前用户ID:$userId'); context.read().loadWorkRecords(userId); @@ -2578,8 +3050,14 @@ class _MapPageEnterpriseState extends State { initialRobotMode: _currentRobotMode, initialAreaMode: _currentAreaMode, initialWorkMode: _currentWorkMode!, - isShowButton: _currentWorkMode == WorkMode.bow ? true : false, - canUndo: _isWorkAreaCompleted && _currentAreaMode == AreaMode.work ? false : true, + isShowButton: _currentWorkMode == WorkMode.bow + ? true + : false, + canUndo: + _isWorkAreaCompleted && + _currentAreaMode == AreaMode.work + ? false + : true, onComplete: () async { debugPrint( '操作完成回调:当前机器人模式=$_currentRobotMode,当前区域模式=$_currentAreaMode,当前作业模式:$_currentWorkMode,作业区域点:$_markedPoints,作业行距=$_workDistance,航线方向角=$_angle', @@ -2617,8 +3095,11 @@ class _MapPageEnterpriseState extends State { }, onDistanceTap: (distance) { _workDistance = distance; - debugPrint('外部处理作业行距距离设置,当前距离:${distance.toStringAsFixed(1)}米'); - if (_markedPoints.length >= 3 && _currentWorkMode != null) { + debugPrint( + '外部处理作业行距距离设置,当前距离:${distance.toStringAsFixed(1)}米', + ); + if (_markedPoints.length >= 3 && + _currentWorkMode != null) { _generatePath(showTips: false); } }, @@ -2645,13 +3126,22 @@ class _MapPageEnterpriseState extends State { child: RouteDirectionPanel( initialOptimalHeading: true, initialDirection: 0.0, - titleText: AppLocalizations.of(context).translate('route_planning.route_direction'), - optimalHeadingText: AppLocalizations.of(context).translate('route_planning.optimal_heading'), - routeDirectionText: AppLocalizations.of(context).translate('route_planning.route_direction'), + titleText: AppLocalizations.of( + context, + ).translate('route_planning.route_direction'), + optimalHeadingText: AppLocalizations.of( + context, + ).translate('route_planning.optimal_heading'), + routeDirectionText: AppLocalizations.of( + context, + ).translate('route_planning.route_direction'), onValueChanged: (result) { - _angle = result['optimalHeading'] == true ? -1 : result['direction']; + _angle = result['optimalHeading'] == true + ? -1 + : result['direction']; - if (_markedPoints.length >= 3 && _currentWorkMode != null) { + if (_markedPoints.length >= 3 && + _currentWorkMode != null) { _generatePath(showTips: false); } }, @@ -2665,7 +3155,9 @@ class _MapPageEnterpriseState extends State { if (_isListBoxOpen) BlocBuilder( builder: (context, state) { - final plotList = _convertWorkRecordsToPlotData(state.workRecords ?? []); + final plotList = _convertWorkRecordsToPlotData( + state.workRecords ?? [], + ); return Positioned.fill( child: Column( @@ -2678,27 +3170,55 @@ class _MapPageEnterpriseState extends State { _isListBoxOpen = false; }); }, - child: Container(color: Colors.black.withOpacity(0.3)), + child: Container( + color: Colors.black.withOpacity(0.3), + ), ), ), Container( width: double.infinity, decoration: const BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.vertical(top: Radius.circular(16)), - boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 10, offset: Offset(0, -2))], + borderRadius: BorderRadius.vertical( + top: Radius.circular(16), + ), + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 10, + offset: Offset(0, -2), + ), + ], + ), + constraints: const BoxConstraints( + maxHeight: 600, + minHeight: 200, ), - constraints: const BoxConstraints(maxHeight: 600, minHeight: 200), child: Column( children: [ Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ Text( - AppLocalizations.of(context).translate('route_planning.plot_list_title').replaceAll('%d', plotList.length.toString()), - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87), + AppLocalizations.of(context) + .translate( + 'route_planning.plot_list_title', + ) + .replaceAll( + '%d', + plotList.length.toString(), + ), + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), ), IconButton( onPressed: () { @@ -2706,7 +3226,11 @@ class _MapPageEnterpriseState extends State { _isListBoxOpen = false; }); }, - icon: const Icon(Icons.close, color: Colors.grey, size: 20), + icon: const Icon( + Icons.close, + color: Colors.grey, + size: 20, + ), ), ], ), @@ -2716,24 +3240,55 @@ class _MapPageEnterpriseState extends State { child: plotList.isEmpty ? Center( child: Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, children: [ - const Icon(Icons.inbox_outlined, color: Colors.grey, size: 48), + const Icon( + Icons.inbox_outlined, + color: Colors.grey, + size: 48, + ), const SizedBox(height: 16), - Text(AppLocalizations.of(context).translate('route_planning.no_plot_data'), style: const TextStyle(color: Colors.grey, fontSize: 16)), + Text( + AppLocalizations.of( + context, + ).translate( + 'route_planning.no_plot_data', + ), + style: const TextStyle( + color: Colors.grey, + fontSize: 16, + ), + ), ], ), ) : ListView.builder( - padding: const EdgeInsets.symmetric(vertical: 8), + padding: const EdgeInsets.symmetric( + vertical: 8, + ), itemCount: plotList.length, itemBuilder: (context, index) { final plot = plotList[index]; // 传入删除回调(调用Bloc的删除方法) - return _buildPlotListItem(plot, (deletedPlot) async { - await context.read().deleteWorkRecord(deletedPlot.plotName); - final userId = context.read().state.user?.userId ?? ""; - await context.read().loadWorkRecords(userId); + return _buildPlotListItem(plot, ( + deletedPlot, + ) async { + await context + .read() + .deleteWorkRecord( + deletedPlot.plotName, + ); + final userId = + context + .read() + .state + .user + ?.userId ?? + ""; + await context + .read() + .loadWorkRecords(userId); setState(() {}); }); @@ -2754,18 +3309,39 @@ class _MapPageEnterpriseState extends State { left: 20, right: 20, child: Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), decoration: BoxDecoration( color: Colors.orange.withOpacity(0.9), borderRadius: BorderRadius.circular(8), - boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 4, offset: const Offset(0, 2))], + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], ), child: Row( children: [ - const Icon(Icons.warning_amber_rounded, color: Colors.white, size: 20), + const Icon( + Icons.warning_amber_rounded, + color: Colors.white, + size: 20, + ), const SizedBox(width: 8), Expanded( - child: Text(AppLocalizations.of(context).translate('route_planning.heading_not_init'), style: const TextStyle(color: Colors.white, fontSize: 14)), + child: Text( + AppLocalizations.of( + context, + ).translate('route_planning.heading_not_init'), + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), ), ], ), @@ -2779,18 +3355,39 @@ class _MapPageEnterpriseState extends State { left: 20, right: 20, child: Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), decoration: BoxDecoration( color: Colors.red.withOpacity(0.9), borderRadius: BorderRadius.circular(8), - boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 4, offset: const Offset(0, 2))], + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], ), child: Row( children: [ - const Icon(Icons.error_rounded, color: Colors.white, size: 20), + const Icon( + Icons.error_rounded, + color: Colors.white, + size: 20, + ), const SizedBox(width: 8), Expanded( - child: Text(AppLocalizations.of(context).translate('route_planning.switch_remote_mode'), style: const TextStyle(color: Colors.white, fontSize: 14)), + child: Text( + AppLocalizations.of( + context, + ).translate('route_planning.switch_remote_mode'), + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), ), ], ), @@ -2918,7 +3515,13 @@ bool _outOfChina(double lat, double lon) { } double _transformLat(double x, double y) { - double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(x.abs()); + double ret = + -100.0 + + 2.0 * x + + 3.0 * y + + 0.2 * y * y + + 0.1 * x * y + + 0.2 * sqrt(x.abs()); ret += (20.0 * sin(6.0 * x * _pi) + 20.0 * sin(2.0 * x * _pi)) * 2.0 / 3.0; ret += (20.0 * sin(y * _pi) + 40.0 * sin(y / 3.0 * _pi)) * 2.0 / 3.0; ret += (160.0 * sin(y / 12.0 * _pi) + 320 * sin(y * _pi / 30.0)) * 2.0 / 3.0; @@ -2926,10 +3529,12 @@ double _transformLat(double x, double y) { } double _transformLon(double x, double y) { - double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(x.abs()); + double ret = + 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(x.abs()); ret += (20.0 * sin(6.0 * x * _pi) + 20.0 * sin(2.0 * x * _pi)) * 2.0 / 3.0; ret += (20.0 * sin(x * _pi) + 40.0 * sin(x / 3.0 * _pi)) * 2.0 / 3.0; - ret += (150.0 * sin(x / 12.0 * _pi) + 300.0 * sin(x / 30.0 * _pi)) * 2.0 / 3.0; + ret += + (150.0 * sin(x / 12.0 * _pi) + 300.0 * sin(x / 30.0 * _pi)) * 2.0 / 3.0; return ret; } @@ -2946,7 +3551,9 @@ String _calculateLatLngDistance(LatLng point1, LatLng point2) { // 哈维正弦公式(Haversine)计算地球表面两点实际距离 double dLat = lat2Rad - lat1Rad; double dLng = lng2Rad - lng1Rad; - double a = sin(dLat / 2) * sin(dLat / 2) + cos(lat1Rad) * cos(lat2Rad) * sin(dLng / 2) * sin(dLng / 2); + double a = + sin(dLat / 2) * sin(dLat / 2) + + cos(lat1Rad) * cos(lat2Rad) * sin(dLng / 2) * sin(dLng / 2); double c = 2 * atan2(sqrt(a), sqrt(1 - a)); double distance = earthRadius * c; diff --git a/pubspec.lock b/pubspec.lock index c691d70b..dc608ad4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: archive - sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff + sha256: "6c5bcd986e06b94e3c40244af471750840a3d2341d1f9763a1100a14add517b4" url: "https://pub.flutter-io.cn" source: hosted - version: "4.0.9" + version: "4.3.0" args: dependency: transitive description: @@ -45,10 +45,10 @@ packages: dependency: "direct main" description: name: bloc - sha256: a48653a82055a900b88cd35f92429f068c5a8057ae9b136d197b3d56c57efb81 + sha256: e03b235924e4f509c27b5d6b2f949200e0a91149a9818b4f65eeb56662b75413 url: "https://pub.flutter-io.cn" source: hosted - version: "9.2.0" + version: "9.2.1" boolean_selector: dependency: transitive description: @@ -61,34 +61,34 @@ packages: dependency: transitive description: name: build - sha256: aadd943f4f8cc946882c954c187e6115a84c98c81ad1d9c6cbf0895a8c85da9c + sha256: "45d14a0fb23e018d8287c32fc98d726ce466b231928ed9b9200f29bd3ccd39ae" url: "https://pub.flutter-io.cn" source: hosted - version: "4.0.5" + version: "4.0.7" build_config: dependency: transitive description: name: build_config - sha256: "4070d2a59f8eec34c97c86ceb44403834899075f66e8a9d59706f8e7834f6f71" + sha256: d466ed2dc9c6cd1d169948879b84ee061eb5e22c64a7c6089879c6296d272a8d url: "https://pub.flutter-io.cn" source: hosted - version: "1.3.0" + version: "1.3.3" build_daemon: dependency: transitive description: name: build_daemon - sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957 + sha256: fd754058c342243718d5171a95f352cfc9fcf0cba8cfa26df67cb13a5836db78 url: "https://pub.flutter-io.cn" source: hosted - version: "4.1.1" + version: "4.1.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "521daf8d189deb79ba474e43a696b41c49fb3987818dbacf3308f1e03673a75e" + sha256: "5367e521935b102bdf1e735d2aab461e36b2edca6517662d088dd04cc39f8d16" url: "https://pub.flutter-io.cn" source: hosted - version: "2.13.1" + version: "2.15.1" built_collection: dependency: transitive description: @@ -101,10 +101,10 @@ packages: dependency: transitive description: name: built_value - sha256: "0730c18c770d05636a8f945c32a4d7d81cb6e0f0148c8db4ad12e7748f7e49af" + sha256: f87ea98192116f7093cb214551ce1929caae0681fdba282b3d8b4462adee7bb7 url: "https://pub.flutter-io.cn" source: hosted - version: "8.12.5" + version: "8.13.0" cc_ui_kit: dependency: "direct main" description: @@ -148,18 +148,10 @@ packages: dependency: transitive description: name: code_assets - sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" - code_builder: - dependency: transitive - description: - name: code_builder - sha256: "6a6cab2ba4680d6423f34a9b972a4c9a94ebe1b62ecec4e1a1f2cba91fd1319d" - url: "https://pub.flutter-io.cn" - source: hosted - version: "4.11.1" + version: "1.2.1" collection: dependency: transitive description: @@ -196,10 +188,10 @@ packages: dependency: transitive description: name: cross_file - sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" + sha256: f141ea4f277af142a0356955707f6556f37b03947d39d55585981a06ca437bd6 url: "https://pub.flutter-io.cn" source: hosted - version: "0.3.5+2" + version: "0.3.5+5" crypto: dependency: transitive description: @@ -236,10 +228,10 @@ packages: dependency: transitive description: name: dart_webrtc - sha256: f6d615bddea5e458ce180a914f3055c234ffb52fb7397a51b3491e76d6d7edb2 + sha256: "078e3c431500147e5cc52b3c6ea41ed538f30c7720cc2467d2186c9251e62716" url: "https://pub.flutter-io.cn" source: hosted - version: "1.8.1" + version: "1.8.2" dartx: dependency: transitive description: @@ -252,10 +244,10 @@ packages: dependency: transitive description: name: dbus - sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 + sha256: a48d5da28e89bd02196e80d81ed8d7954923d00a0f4a68cc20b575038f023383 url: "https://pub.flutter-io.cn" source: hosted - version: "0.7.12" + version: "0.7.15" device_info_plus: dependency: "direct main" description: @@ -276,26 +268,26 @@ packages: dependency: "direct main" description: name: dio - sha256: aff32c08f92787a557dd5c0145ac91536481831a01b4648136373cddb0e64f8c + sha256: "852ec3b48cc431ac04fff978413c541502b67ffc3e26921e74e3d994694192c1" url: "https://pub.flutter-io.cn" source: hosted - version: "5.9.2" + version: "5.11.1" dio_web_adapter: dependency: transitive description: name: dio_web_adapter - sha256: "2f9e64323a7c3c7ef69567d5c800424a11f8337b8b228bad02524c9fb3c1f340" + sha256: "3a1b2cd7be71086f38504956e3ebcd2837288d231ff454bafa78021244102bfc" url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.2" + version: "2.2.2" equatable: dependency: "direct main" description: name: equatable - sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" + sha256: "3bce007a596ff8b3119c45d68aaef631272537c03d30e5d4534dd24bf4c5eaa2" url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.8" + version: "2.1.0" fake_async: dependency: transitive description: @@ -324,18 +316,18 @@ packages: dependency: transitive description: name: file_selector_linux - sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" + sha256: da76400e7872ce7637ffdce12749ec24169c25f6195c28372208e65a24bcd2ab url: "https://pub.flutter-io.cn" source: hosted - version: "0.9.4" + version: "0.9.4+1" file_selector_macos: dependency: transitive description: name: file_selector_macos - sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" + sha256: d57c62362766b5e7ae739448650b66c6aab7a68ba7ecc65e04018652645ae0f4 url: "https://pub.flutter-io.cn" source: hosted - version: "0.9.5" + version: "0.9.5+1" file_selector_platform_interface: dependency: transitive description: @@ -348,10 +340,10 @@ packages: dependency: transitive description: name: file_selector_windows - sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" + sha256: fbefc5fb92c6d3cbe8d284a2cd971b593bb07d2cd6da8557b81a862250b4acec url: "https://pub.flutter-io.cn" source: hosted - version: "0.9.3+5" + version: "0.9.3+6" fixnum: dependency: transitive description: @@ -430,18 +422,18 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "38d1c268de9097ff59cf0e844ac38759fc78f76836d37edad06fa21e182055a0" + sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785" url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.34" + version: "2.0.35" flutter_svg: dependency: "direct main" description: name: flutter_svg - sha256: "1ded017b39c8e15c8948ea855070a5ff8ff8b3d5e83f3446e02d6bb12add7ad9" + sha256: "35882981abcbfb8c15b286f0cd690ff25bac12d95eff3e25ee207f37d4c42e7f" url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.4" + version: "2.3.0" flutter_test: dependency: "direct dev" description: flutter @@ -456,10 +448,10 @@ packages: dependency: "direct main" description: name: flutter_webrtc - sha256: c7b0a67ca2c878575fc5c146d801cd874f58f5f1ef5fa6e8eb0c93d413beb948 + sha256: "381e05c120caf2f1ee1accd806baad22b33802f36c74d8ea5e43a5800ce6380c" url: "https://pub.flutter-io.cn" source: hosted - version: "1.4.1" + version: "1.6.2+hotfix.1" fpdart: dependency: "direct main" description: @@ -488,26 +480,26 @@ packages: dependency: transitive description: name: geolocator_apple - sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 + sha256: "853803d6bb1713c094e935b4a5ae5f19c0308acf81da13fa9ff84fb4c70c0b73" url: "https://pub.flutter-io.cn" source: hosted - version: "2.3.13" + version: "2.3.14" geolocator_platform_interface: dependency: transitive description: name: geolocator_platform_interface - sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" + sha256: "94db8255dc183d268765df682580440617ca35877fc82cacb5420ad03b86198d" url: "https://pub.flutter-io.cn" source: hosted - version: "4.2.6" + version: "4.3.0" geolocator_web: dependency: transitive description: name: geolocator_web - sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 + sha256: "19e485a0f8d6a88abcf9c53cba3a4105e14b7435ed8ac1c108c067b938fe8429" url: "https://pub.flutter-io.cn" source: hosted - version: "4.1.3" + version: "4.1.4" geolocator_windows: dependency: transitive description: @@ -528,26 +520,26 @@ packages: dependency: transitive description: name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + sha256: "218aeb56050c714f62a3182775320dfa04602b55074873e24e31bbd39bda96fb" url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.3" + version: "2.2.0" go_router: dependency: "direct main" description: name: go_router - sha256: "7974313e217a7771557add6ff2238acb63f635317c35fa590d348fb238f00896" + sha256: d7a3576cb312649eaa51f2356450aed686085fb58fcdebda5b359aa951eef7ea url: "https://pub.flutter-io.cn" source: hosted - version: "17.1.0" + version: "17.5.0" google_fonts: dependency: "direct main" description: name: google_fonts - sha256: db9df7a5898d894eeda4c78143f35c30a243558be439518972366880b80bf88e + sha256: e3cb3ee6b47fd2472c23de6da5744796a4da195137759ddb3fbcc9467b7b3c7d url: "https://pub.flutter-io.cn" source: hosted - version: "8.0.2" + version: "8.2.1" google_nav_bar: dependency: "direct main" description: @@ -576,10 +568,10 @@ packages: dependency: transitive description: name: hooks - sha256: e79ed1e8e1929bc6ecb6ec85f0cb519c887aa5b423705ded0d0f2d9226def388 + sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.2" + version: "2.0.2" http: dependency: "direct main" description: @@ -608,26 +600,26 @@ packages: dependency: "direct main" description: name: image - sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce + sha256: a1e7f4951e538a568e14b856702afc9ae1d2f4b202daced8d22c1b9cd211ce89 url: "https://pub.flutter-io.cn" source: hosted - version: "4.8.0" + version: "4.10.1" image_picker: dependency: "direct main" description: name: image_picker - sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320" + sha256: d8402284df184bc05f4a2210c6c23983b0720f4cd87cbd05c5390a78af602667 url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.1" + version: "1.2.3" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "9eae0cbd672549dacc18df855c2a23782afe4854ada5190b7d63b30ee0b0d3fd" + sha256: d5b3e1774af29c9ab00103afb0d4614070f924d2e0057ac867ec98800114793f url: "https://pub.flutter-io.cn" source: hosted - version: "0.8.13+15" + version: "0.8.13+17" image_picker_for_web: dependency: transitive description: @@ -640,10 +632,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: b9c4a438a9ff4f60808c9cf0039b93a42bb6c2211ef6ebb647394b2b3fa84588 + sha256: ee3885b6fcd71958fbc79770dd194c63371439d536d69c47b279171a486482ae url: "https://pub.flutter-io.cn" source: hosted - version: "0.8.13+6" + version: "0.8.13+7" image_picker_linux: dependency: transitive description: @@ -688,10 +680,10 @@ packages: dependency: transitive description: name: io - sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + sha256: "2635216ca6a737e60de577ffa1a48a0bec76ca8a62917cfc1bb88c14c570646f" url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.5" + version: "1.1.0" isar_community: dependency: "direct main" description: @@ -736,10 +728,10 @@ packages: dependency: transitive description: name: json_annotation - sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8 + sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80" url: "https://pub.flutter-io.cn" source: hosted - version: "4.11.0" + version: "4.12.0" latlong2: dependency: "direct main" description: @@ -792,10 +784,10 @@ packages: dependency: "direct main" description: name: logger - sha256: "25aee487596a6257655a1e091ec2ae66bc30e7af663592cc3a27e6591e05035c" + sha256: "2a0dc097e7b01d942475bdd552356db2d0f768b05540bd4b2b53f1840f2239a7" url: "https://pub.flutter-io.cn" source: hosted - version: "2.7.0" + version: "2.8.0" logging: dependency: transitive description: @@ -856,10 +848,10 @@ packages: dependency: transitive description: name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + sha256: bd47de35f07e27267e69c8c8b22edf9473bfee170a60d60fcc93730c5144b7f6 url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "2.1.0" mobile_scanner: dependency: "direct dev" description: @@ -868,14 +860,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.5.7" - native_toolchain_c: - dependency: transitive - description: - name: native_toolchain_c - sha256: "6ba77bb18063eebe9de401f5e6437e95e1438af0a87a3a39084fbd37c90df572" - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.17.6" nested: dependency: transitive description: @@ -896,10 +880,10 @@ packages: dependency: transitive description: name: objective_c - sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" + sha256: b7fb95a6d9a4f009edd63dc5ac69f07420b23a16161c6dd8660290b59c602e8e url: "https://pub.flutter-io.cn" source: hosted - version: "9.3.0" + version: "9.5.0" package_config: dependency: transitive description: @@ -944,10 +928,10 @@ packages: dependency: "direct main" description: name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + sha256: a7f4874f987173da295a61c181b8ee71dab59b332a486b391babf26a1b884825 url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.5" + version: "2.1.6" path_provider_android: dependency: transitive description: @@ -968,18 +952,18 @@ packages: dependency: transitive description: name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + sha256: "58c2005f147315b11e9b4a7bc889cd5203e250cba8e3f012dae259b4972b5c16" url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.1" + version: "2.2.2" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + sha256: "484838772624c3a4b94f1e44a3e19897fee738f2d5c4ce448443b0417f7c9dda" url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.2" + version: "2.1.3" path_provider_windows: dependency: transitive description: @@ -992,10 +976,10 @@ packages: dependency: "direct main" description: name: permission_handler - sha256: bc917da36261b00137bbc8896bf1482169cd76f866282368948f032c8c1caae1 + sha256: fe54465bcc62a4564c6e4db337bbaded6c0c0fa6e10487414436d163114784f6 url: "https://pub.flutter-io.cn" source: hosted - version: "12.0.1" + version: "12.0.3" permission_handler_android: dependency: transitive description: @@ -1008,34 +992,34 @@ packages: dependency: transitive description: name: permission_handler_apple - sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 + sha256: f49cb15a064ea9d974fc7fbb302099353b7b170d07284e86e264561579e5bcf8 url: "https://pub.flutter-io.cn" source: hosted - version: "9.4.7" + version: "9.6.1" permission_handler_html: dependency: transitive description: name: permission_handler_html - sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" + sha256: "6ea98b3f17f60d3b527f2647ed2ab4dc0f6bfe25b22cb1c363f5d8f62252f6ac" url: "https://pub.flutter-io.cn" source: hosted - version: "0.1.3+5" + version: "0.1.4+1" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 + sha256: ed86a61c190258fdd65de395ea0632822e3415c1faec38eae0c31b479c28a531 url: "https://pub.flutter-io.cn" source: hosted - version: "4.3.0" + version: "4.4.1" permission_handler_windows: dependency: transitive description: name: permission_handler_windows - sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + sha256: caeae01858a0a7d2df67a445ac98e1ad95e55a0e77c73044f4e9b1c8c2289cbd url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.1" + version: "0.2.2" petitparser: dependency: transitive description: @@ -1072,18 +1056,18 @@ packages: dependency: transitive description: name: pool - sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + sha256: "4177f68c237ea2128d1bee66ac17b2ce05ba3dbaafcbdd54c5d40a39d0b6b11c" url: "https://pub.flutter-io.cn" source: hosted - version: "1.5.2" + version: "1.5.3" posix: dependency: transitive description: name: posix - sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" + sha256: bc1bad54ad2b735816e31f8d4600cfde6c7839975085ddfbca48b6c9f7c4044e url: "https://pub.flutter-io.cn" source: hosted - version: "6.5.0" + version: "6.5.2" proj4dart: dependency: transitive description: @@ -1104,18 +1088,26 @@ packages: dependency: transitive description: name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + sha256: "261236774e8b1d69cfc6b9eabbc96c40f25e7a2d6b171f3385d4f65d5734fb24" url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.0" + version: "2.2.1" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + sha256: c38b81cbf34450b67e0265d73433569d12e34782e30ed769c9cc99c9d5f2e796 url: "https://pub.flutter-io.cn" source: hosted - version: "1.5.0" + version: "1.6.0" + record_use: + dependency: transitive + description: + name: record_use + sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.0" scroll_to_index: dependency: transitive description: @@ -1128,18 +1120,18 @@ packages: dependency: transitive description: name: sentry - sha256: "288aee3d35f252ac0dc3a4b0accbbe7212fa2867604027f2cc5bc65334afd743" + sha256: f04095a25ff02b202a914174c73ec309570aa93d61098cb4a0a9e715b4aaa465 url: "https://pub.flutter-io.cn" source: hosted - version: "9.16.0" + version: "9.20.0" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: f9e87d5895cc437902aa2b081727ee7e46524fe7cc2e1910f535480a3eeb8bed + sha256: "4f0a914d8c37e5015d7b86dd42b92dd265948fd31875b43e62ddfc2e7bea0e41" url: "https://pub.flutter-io.cn" source: hosted - version: "9.16.0" + version: "9.20.0" shared_preferences: dependency: "direct main" description: @@ -1160,10 +1152,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" + sha256: "2ec3934efa51e46117f23031cc141b8fc878e8525b94ec1ea4f7f586cf1b47ea" url: "https://pub.flutter-io.cn" source: hosted - version: "2.5.6" + version: "2.5.7" shared_preferences_linux: dependency: transitive description: @@ -1221,10 +1213,10 @@ packages: dependency: transitive description: name: source_gen - sha256: "732792cfd197d2161a65bb029606a46e0a18ff30ef9e141a7a82172b05ea8ecd" + sha256: a603f1fb984a7391ae5978d1b92bfaaa08b350dca5c825256f925818f7943bf5 url: "https://pub.flutter-io.cn" source: hosted - version: "4.2.2" + version: "4.2.4" source_span: dependency: transitive description: @@ -1253,10 +1245,10 @@ packages: dependency: transitive description: name: stream_transform - sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + sha256: a00e5f18bffc764f923e7dec1038527f7fe7a1791361a7117f0358193f13d53a url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -1341,34 +1333,34 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "3bb000251e55d4a209aa0e2e563309dc9bb2befea2295fd0cec1f51760aac572" + sha256: "17bc677f0b301615530dd1d67e0a9828cafa2d0b6b6eae4cd3679b7eac4a273c" url: "https://pub.flutter-io.cn" source: hosted - version: "6.3.29" + version: "6.3.30" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" + sha256: "8faa1aab294f1ab4040b43660c887b0418d5fa4f0cffef76a484e6aa1092eb4a" url: "https://pub.flutter-io.cn" source: hosted - version: "6.4.1" + version: "6.4.2" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a + sha256: "10f86fef4c2c43563fa6c211ff9cf757adf4d3ab762c56bd430664a947d70cd0" url: "https://pub.flutter-io.cn" source: hosted - version: "3.2.2" + version: "3.2.3" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" + sha256: "5e835a3b869c2d70325349c81c5a45c28e20791265b67b2669da6b08c5cd5201" url: "https://pub.flutter-io.cn" source: hosted - version: "3.2.5" + version: "3.2.6" url_launcher_platform_interface: dependency: transitive description: @@ -1381,34 +1373,34 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f + sha256: "85c81589622fbc87c1c683aaea164d3604a7777495a79d91e39ffcdec39ddb34" url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.2" + version: "2.4.3" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" + sha256: "6c5ad3f22cd4c38e089b81963b3cd7bb83b111b2df5dce008bb066162f42e429" url: "https://pub.flutter-io.cn" source: hosted - version: "3.1.5" + version: "3.1.6" uuid: dependency: transitive description: name: uuid - sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" + sha256: "9b129329f58692f6e6578329498a8fe9fbe98f090beb764ffbb8ee2eadd01dcd" url: "https://pub.flutter-io.cn" source: hosted - version: "4.5.3" + version: "4.6.0" vector_graphics: dependency: transitive description: name: vector_graphics - sha256: "81da85e9ca8885ade47f9685b953cb098970d11be4821ac765580a6607ea4373" + sha256: "9d0e3b9cb16542ad660daee871e726a10d13a93b7b5391677c3160e8f5e83935" url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.21" + version: "1.2.3" vector_graphics_codec: dependency: transitive description: @@ -1421,10 +1413,10 @@ packages: dependency: transitive description: name: vector_graphics_compiler - sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" + sha256: "4dca4feb77dc3ec7f6e27e49c53241eb8217f55e4f9b12599a27f8903bca5682" url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.0" + version: "1.3.0" vector_math: dependency: transitive description: @@ -1445,10 +1437,10 @@ packages: dependency: transitive description: name: vibration_platform_interface - sha256: "4134fbfcd427b59a7a91f8733292e4e9b29a7f1e8224ff0d80f5745fbf0743c6" + sha256: "258c273268f8aa40c88d29741137c536874a738779b92ddb8aa32ed093721ec5" url: "https://pub.flutter-io.cn" source: hosted - version: "0.1.1" + version: "0.1.2" visibility_detector: dependency: transitive description: @@ -1461,10 +1453,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + sha256: "5f37239c4851efcef929cea7824e76df7f2f0970aef85d66bbc430afa40e72f0" url: "https://pub.flutter-io.cn" source: hosted - version: "15.0.2" + version: "15.3.0" watcher: dependency: transitive description: @@ -1509,18 +1501,18 @@ packages: dependency: "direct main" description: name: webview_flutter - sha256: a3da219916aba44947d3a5478b1927876a09781174b5a2b67fa5be0555154bf9 + sha256: d53e1ccf5516f25017e3c9d44c39034db352d20fa34fe200674270242c2c5111 url: "https://pub.flutter-io.cn" source: hosted - version: "4.13.1" + version: "4.14.1" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: "0f7fcd2c86bf36bdcf94881f7941ce0cbc4f8d104b9fdcd5fcbef90e2199db76" + sha256: ad5182eff9a550925330cb9f0cb038eddfdd5712aba8b77aa0f0400e50f6e688 url: "https://pub.flutter-io.cn" source: hosted - version: "4.10.15" + version: "4.12.0" webview_flutter_platform_interface: dependency: transitive description: @@ -1533,10 +1525,10 @@ packages: dependency: transitive description: name: webview_flutter_wkwebview - sha256: d7219cfabc6f5fc2032e0fa980ec36d71f308a35a823395af1abc34d9a2ede83 + sha256: "82648217f537573e1ca9ae9952d3eacedca6ab5aee69dc84445fc763766dcea2" url: "https://pub.flutter-io.cn" source: hosted - version: "3.24.2" + version: "3.25.1" win32: dependency: transitive description: @@ -1589,10 +1581,10 @@ packages: dependency: transitive description: name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + sha256: f67cdd8e07d3c6329146aaef1ba043542b3134c12489f553ca9a7435d1068aea url: "https://pub.flutter-io.cn" source: hosted - version: "3.1.3" + version: "3.1.4" sdks: dart: ">=3.10.3 <4.0.0" flutter: ">=3.38.4" diff --git a/pubspec.yaml b/pubspec.yaml index b411ebc5..d0269e7e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -100,7 +100,7 @@ dependencies: flutter_webrtc: ^1.2.1 # ===== 日志存储 ===== - sentry_flutter: ^9.10.0 + sentry_flutter: 9.20.0 # ===== 设备信息 ===== device_info_plus: ^12.3.0