| 
									
										
										
										
											2025-08-21 16:44:24 +08:00
										 |  |  |  | import 'dart:convert'; | 
					
						
							|  |  |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  |  | import 'package:qhd_prevention/customWidget/BaiDuMap/BaiduMapWebView.dart'; | 
					
						
							|  |  |  |  | import 'package:qhd_prevention/customWidget/toast_util.dart'; | 
					
						
							|  |  |  |  | import 'package:qhd_prevention/pages/my_appbar.dart'; | 
					
						
							|  |  |  |  | import 'package:qhd_prevention/services/location_service.dart'; | 
					
						
							| 
									
										
										
										
											2025-09-02 16:22:17 +08:00
										 |  |  |  | import 'package:qhd_prevention/tools/coord_convert.dart'; | 
					
						
							| 
									
										
										
										
											2025-08-21 16:44:24 +08:00
										 |  |  |  | import 'package:qhd_prevention/tools/tools.dart'; | 
					
						
							| 
									
										
										
										
											2025-09-02 16:22:17 +08:00
										 |  |  |  | import 'package:shared_preferences/shared_preferences.dart'; | 
					
						
							| 
									
										
										
										
											2025-08-21 16:44:24 +08:00
										 |  |  |  | import 'package:webview_flutter/webview_flutter.dart'; | 
					
						
							|  |  |  |  | import 'package:geolocator/geolocator.dart'; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | class MapPage extends StatefulWidget { | 
					
						
							|  |  |  |  |   final String gson; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   const MapPage({super.key, required this.gson}); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   @override | 
					
						
							|  |  |  |  |   State<MapPage> createState() => _MapPageState(); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | class _MapPageState extends State<MapPage> { | 
					
						
							|  |  |  |  |   late final WebViewController _controller; | 
					
						
							|  |  |  |  |   bool _isLoading = true; | 
					
						
							|  |  |  |  |   String? _errorMessage; | 
					
						
							|  |  |  |  |   double? _longitude; | 
					
						
							|  |  |  |  |   double? _latitude; | 
					
						
							|  |  |  |  |   List<dynamic> _gsonList = []; | 
					
						
							|  |  |  |  |   late Map<String, dynamic> mapData = {}; | 
					
						
							|  |  |  |  |   @override | 
					
						
							|  |  |  |  |   void initState() { | 
					
						
							|  |  |  |  |     super.initState(); | 
					
						
							| 
									
										
										
										
											2025-09-05 09:16:54 +08:00
										 |  |  |  |     _loadWebView(); | 
					
						
							| 
									
										
										
										
											2025-08-21 16:44:24 +08:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /// 获取定位(并初始化 WebView 控制器)
 | 
					
						
							| 
									
										
										
										
											2025-09-05 09:16:54 +08:00
										 |  |  |  |   // Future<void> _initLocation() async {
 | 
					
						
							|  |  |  |  |   //   setState(() {
 | 
					
						
							|  |  |  |  |   //     _isLoading = true;
 | 
					
						
							|  |  |  |  |   //     _errorMessage = null;
 | 
					
						
							|  |  |  |  |   //   });
 | 
					
						
							|  |  |  |  |   //   Map<String, double> prefs = geographicCentroid(_gsonList);
 | 
					
						
							|  |  |  |  |   //   _loadWebView(LocationResult(latitude: prefs['lat'].toString(), longitude: prefs['lon'].toString()));
 | 
					
						
							|  |  |  |  |   //
 | 
					
						
							|  |  |  |  |   // }
 | 
					
						
							|  |  |  |  |   Future<void> _loadWebView() async { | 
					
						
							| 
									
										
										
										
											2025-09-02 16:22:17 +08:00
										 |  |  |  |     // 解析 gson
 | 
					
						
							|  |  |  |  |     try { | 
					
						
							|  |  |  |  |       final parsed = jsonDecode(widget.gson); | 
					
						
							|  |  |  |  |       if (parsed is List) { | 
					
						
							|  |  |  |  |         _gsonList = parsed; | 
					
						
							|  |  |  |  |       } else { | 
					
						
							|  |  |  |  |         _gsonList = []; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     } catch (e) { | 
					
						
							|  |  |  |  |       debugPrint('解析 gson 失败: $e'); | 
					
						
							|  |  |  |  |       _gsonList = []; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (!mounted) return; | 
					
						
							| 
									
										
										
										
											2025-09-05 09:16:54 +08:00
										 |  |  |  |     Map<String, double> prefs = geographicCentroid(_gsonList); | 
					
						
							|  |  |  |  |     // _loadWebView(LocationResult(latitude: prefs['lat'].toString(), longitude: prefs['lon'].toString()));
 | 
					
						
							| 
									
										
										
										
											2025-09-02 16:22:17 +08:00
										 |  |  |  |     setState(() { | 
					
						
							| 
									
										
										
										
											2025-09-05 09:16:54 +08:00
										 |  |  |  |       _longitude = prefs['lon']; | 
					
						
							|  |  |  |  |       _latitude = prefs['lat']; | 
					
						
							| 
									
										
										
										
											2025-09-02 16:22:17 +08:00
										 |  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2025-09-05 09:16:54 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-02 16:22:17 +08:00
										 |  |  |  |     // 初始化 WebViewController 并加载本地页面
 | 
					
						
							|  |  |  |  |     _controller = WebViewController() | 
					
						
							|  |  |  |  |       ..setJavaScriptMode(JavaScriptMode.unrestricted) | 
					
						
							|  |  |  |  |     // 注册 JS 通道 'JS' —— 对应 HTML 中的 window.JS.postMessage(...)
 | 
					
						
							|  |  |  |  |       ..addJavaScriptChannel('JS', onMessageReceived: (dynamic message) { | 
					
						
							|  |  |  |  |         // message 是动态对象,不在签名中引用具体类型以避免 "Undefined class" 问题
 | 
					
						
							|  |  |  |  |         String payload; | 
					
						
							|  |  |  |  |         try { | 
					
						
							|  |  |  |  |           payload = message.message ?? message.toString(); | 
					
						
							|  |  |  |  |         } catch (e) { | 
					
						
							|  |  |  |  |           payload = message.toString(); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         _onJsMessage(payload); | 
					
						
							|  |  |  |  |       }) | 
					
						
							|  |  |  |  |     // 也保留一个备用通道 'Flutter'
 | 
					
						
							|  |  |  |  |       ..addJavaScriptChannel('Flutter', onMessageReceived: (dynamic message) { | 
					
						
							|  |  |  |  |         String payload; | 
					
						
							|  |  |  |  |         try { | 
					
						
							|  |  |  |  |           payload = message.message ?? message.toString(); | 
					
						
							|  |  |  |  |         } catch (e) { | 
					
						
							|  |  |  |  |           payload = message.toString(); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         _onJsMessage(payload); | 
					
						
							|  |  |  |  |       }) | 
					
						
							|  |  |  |  |       ..setNavigationDelegate( | 
					
						
							|  |  |  |  |         NavigationDelegate( | 
					
						
							|  |  |  |  |           onPageFinished: (String url) async { | 
					
						
							|  |  |  |  |             debugPrint('网页加载完成: $url'); | 
					
						
							|  |  |  |  |             await _injectLocationParams(); | 
					
						
							|  |  |  |  |           }, | 
					
						
							|  |  |  |  |           onWebResourceError: (err) { | 
					
						
							|  |  |  |  |             debugPrint('Web resource error: ${err.description}'); | 
					
						
							|  |  |  |  |           }, | 
					
						
							|  |  |  |  |         ), | 
					
						
							|  |  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2025-08-21 16:44:24 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-02 16:22:17 +08:00
										 |  |  |  |     // 加载本地 assets 中的 HTML
 | 
					
						
							|  |  |  |  |     // await _controller.loadFlutterAsset('assets/map/index.html');
 | 
					
						
							|  |  |  |  |     await _controller.loadRequest(Uri.parse('http://47.92.102.56:7811/file/fluteightmap/index.html')); | 
					
						
							| 
									
										
										
										
											2025-08-21 16:44:24 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-02 16:22:17 +08:00
										 |  |  |  |     setState(() { | 
					
						
							|  |  |  |  |       _isLoading = false; | 
					
						
							|  |  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2025-08-21 16:44:24 +08:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /// 注入参数并调用页面初始化函数 window.initWithData(...)
 | 
					
						
							|  |  |  |  |   Future<void> _injectLocationParams() async { | 
					
						
							|  |  |  |  |     if (_longitude == null || _latitude == null) { | 
					
						
							|  |  |  |  |       debugPrint('位置尚未准备好,跳过注入'); | 
					
						
							|  |  |  |  |       return; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     final params = { | 
					
						
							|  |  |  |  |       'longitude': _longitude, | 
					
						
							|  |  |  |  |       'latitude': _latitude, | 
					
						
							|  |  |  |  |       'GSON': _gsonList, | 
					
						
							|  |  |  |  |       't': DateTime.now().millisecondsSinceEpoch, | 
					
						
							|  |  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2025-09-05 09:16:54 +08:00
										 |  |  |  |     debugPrint('网页初始化参数: ${jsonEncode(params)}'); | 
					
						
							| 
									
										
										
										
											2025-08-21 16:44:24 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     final jsonParams = jsonEncode(params); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     try { | 
					
						
							|  |  |  |  |       await _controller.runJavaScript('''
 | 
					
						
							|  |  |  |  |         (function(){ | 
					
						
							|  |  |  |  |           try { | 
					
						
							|  |  |  |  |             if (typeof window.initWithData === 'function') { | 
					
						
							|  |  |  |  |               window.initWithData($jsonParams); | 
					
						
							|  |  |  |  |             } else if (typeof window.initMap === 'function') { | 
					
						
							|  |  |  |  |               window.initMap($jsonParams); | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |               console.error('initWithData / initMap function not found'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |           } catch(e) { | 
					
						
							|  |  |  |  |             console.error('call initWithData error', e); | 
					
						
							|  |  |  |  |           } | 
					
						
							|  |  |  |  |         })(); | 
					
						
							|  |  |  |  |       ''');
 | 
					
						
							|  |  |  |  |       debugPrint('已注入地图初始化参数'); | 
					
						
							|  |  |  |  |     } catch (e) { | 
					
						
							|  |  |  |  |       debugPrint('注入位置参数失败: $e'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /// 处理来自 Web 的消息(字符串或 JSON)
 | 
					
						
							|  |  |  |  |   void _onJsMessage(String message) { | 
					
						
							|  |  |  |  |     debugPrint('收到来自 Web 的消息: $message'); | 
					
						
							|  |  |  |  |     if (message.isEmpty) return; | 
					
						
							|  |  |  |  |     try { | 
					
						
							|  |  |  |  |       Map<String,dynamic> data = jsonDecode(message); | 
					
						
							|  |  |  |  |       if (FormUtils.hasValue(data, 'ok') && data['ok'] == true) { | 
					
						
							|  |  |  |  |       }else{ | 
					
						
							|  |  |  |  |         if (FormUtils.hasValue(data, 'type') && data['type'] == 'converted') { | 
					
						
							|  |  |  |  |           setState(() { | 
					
						
							|  |  |  |  |             mapData = data; | 
					
						
							|  |  |  |  |           }); | 
					
						
							|  |  |  |  |         }else{ | 
					
						
							|  |  |  |  |           ToastUtil.showNormal(context, '当前选择点位不在区域中'); | 
					
						
							|  |  |  |  |           setState(() { | 
					
						
							|  |  |  |  |             mapData = {}; | 
					
						
							|  |  |  |  |           }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     } catch (_) { | 
					
						
							|  |  |  |  |       setState(() { | 
					
						
							|  |  |  |  |         mapData = {}; | 
					
						
							|  |  |  |  |       }); | 
					
						
							|  |  |  |  |       ToastUtil.showNormal(context, '当前选择点位不在区域中'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   @override | 
					
						
							|  |  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |  |     return Scaffold( | 
					
						
							|  |  |  |  |       appBar: MyAppbar(title: '地图选择', actions: [ | 
					
						
							|  |  |  |  |         if (mapData.isNotEmpty) | 
					
						
							|  |  |  |  |          TextButton(onPressed: (){ | 
					
						
							|  |  |  |  |            Navigator.of(context).pop((mapData)); | 
					
						
							|  |  |  |  |          }, child: Text('确定', style: TextStyle(color: Colors.white, fontSize: 17),)) | 
					
						
							|  |  |  |  |       ],), | 
					
						
							|  |  |  |  |       body: SafeArea( | 
					
						
							|  |  |  |  |         child: BaiduMapWebView( | 
					
						
							|  |  |  |  |         controller: _isLoading || _errorMessage != null ? null : _controller, | 
					
						
							|  |  |  |  |         isLoading: _isLoading, | 
					
						
							|  |  |  |  |         errorMessage: _errorMessage, | 
					
						
							| 
									
										
										
										
											2025-09-05 09:16:54 +08:00
										 |  |  |  |         onRetry: _loadWebView, | 
					
						
							| 
									
										
										
										
											2025-08-21 16:44:24 +08:00
										 |  |  |  |       ),), | 
					
						
							|  |  |  |  |     ); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } |