206 lines
6.1 KiB
Dart
206 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/tools.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();
|
||
_initLocation();
|
||
}
|
||
|
||
/// 获取定位(并初始化 WebView 控制器)
|
||
Future<void> _initLocation() async {
|
||
setState(() {
|
||
_isLoading = true;
|
||
_errorMessage = null;
|
||
});
|
||
LoadingDialogHelper.show(message: '地图加载中');
|
||
try {
|
||
final LocationResult loc = await LocationService.getCurrentLocation(
|
||
timeout: const Duration(seconds: 10),
|
||
);
|
||
|
||
// 解析 gson
|
||
try {
|
||
final parsed = jsonDecode(widget.gson);
|
||
if (parsed is List) {
|
||
_gsonList = parsed;
|
||
} else {
|
||
_gsonList = [];
|
||
}
|
||
} catch (e) {
|
||
debugPrint('解析 gson 失败: $e');
|
||
_gsonList = [];
|
||
}
|
||
|
||
if (!mounted) return;
|
||
|
||
setState(() {
|
||
_longitude = loc.longitudeAsDouble;
|
||
_latitude = loc.latitudeAsDouble;
|
||
});
|
||
|
||
|
||
// 初始化 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 {
|
||
LoadingDialogHelper.hide();
|
||
|
||
debugPrint('网页加载完成: $url');
|
||
await _injectLocationParams();
|
||
},
|
||
onWebResourceError: (err) {
|
||
debugPrint('Web resource error: ${err.description}');
|
||
},
|
||
),
|
||
);
|
||
|
||
// 加载本地 assets 中的 HTML
|
||
// await _controller.loadFlutterAsset('assets/map/test_baidu_map.html');
|
||
await _controller.loadRequest(Uri.parse('http://47.92.102.56:7811/file/fluteightmap/index.html'));
|
||
|
||
setState(() {
|
||
_isLoading = false;
|
||
});
|
||
} catch (e, st) {
|
||
debugPrint('获取位置或初始化失败: $e\n$st');
|
||
if (!mounted) return;
|
||
setState(() {
|
||
_errorMessage = '获取位置失败: ${e.toString()}';
|
||
_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,
|
||
};
|
||
|
||
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: _initLocation,
|
||
),),
|
||
);
|
||
}
|
||
}
|