198 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			198 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Dart
		
	
	
| 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';
 | ||
| import 'package:qhd_prevention/tools/coord_convert.dart';
 | ||
| import 'package:qhd_prevention/tools/tools.dart';
 | ||
| import 'package:shared_preferences/shared_preferences.dart';
 | ||
| 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();
 | ||
|     _loadWebView();
 | ||
|   }
 | ||
| 
 | ||
|   /// 获取定位(并初始化 WebView 控制器)
 | ||
|   // 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 {
 | ||
|     // 解析 gson
 | ||
|     try {
 | ||
|       final parsed = jsonDecode(widget.gson);
 | ||
|       if (parsed is List) {
 | ||
|         _gsonList = parsed;
 | ||
|       } else {
 | ||
|         _gsonList = [];
 | ||
|       }
 | ||
|     } catch (e) {
 | ||
|       debugPrint('解析 gson 失败: $e');
 | ||
|       _gsonList = [];
 | ||
|     }
 | ||
|     if (!mounted) return;
 | ||
|     Map<String, double> prefs = geographicCentroid(_gsonList);
 | ||
|     // _loadWebView(LocationResult(latitude: prefs['lat'].toString(), longitude: prefs['lon'].toString()));
 | ||
|     setState(() {
 | ||
|       _longitude = prefs['lon'];
 | ||
|       _latitude = prefs['lat'];
 | ||
|     });
 | ||
| 
 | ||
| 
 | ||
|     // 初始化 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}');
 | ||
|           },
 | ||
|         ),
 | ||
|       );
 | ||
| 
 | ||
|     // 加载本地 assets 中的 HTML
 | ||
|     // await _controller.loadFlutterAsset('assets/map/index.html');
 | ||
|     await _controller.loadRequest(Uri.parse('http://47.92.102.56:7811/file/fluteightmap/index.html'));
 | ||
| 
 | ||
|     setState(() {
 | ||
|       _isLoading = false;
 | ||
|     });
 | ||
|   }
 | ||
| 
 | ||
|   /// 注入参数并调用页面初始化函数 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,
 | ||
|     };
 | ||
|     debugPrint('网页初始化参数: ${jsonEncode(params)}');
 | ||
| 
 | ||
|     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,
 | ||
|         onRetry: _loadWebView,
 | ||
|       ),),
 | ||
|     );
 | ||
|   }
 | ||
| }
 |