204 lines
6.0 KiB
Dart
204 lines
6.0 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;
|
|||
|
});
|
|||
|
|
|||
|
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 {
|
|||
|
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,
|
|||
|
),),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|