对接路径规划的列表(根据场站的下的)
优化无人机机场的监控视频的显示视频流畅度提升80% 添加首页tcp指示灯的机器状态信息展示功能。(暂不支持在此页面上设备的切换显示)
This commit is contained in:
237
lib/features/devices/data/models/work_record_entity.dart
Normal file
237
lib/features/devices/data/models/work_record_entity.dart
Normal file
@@ -0,0 +1,237 @@
|
||||
/// 工作记录实体(用于XML解析)
|
||||
class WorkRecordEntity {
|
||||
final String? createBy;
|
||||
final String? createTime;
|
||||
final String? updateBy;
|
||||
final String? updateTime;
|
||||
final bool delFlag;
|
||||
final String? remark;
|
||||
final int orgId;
|
||||
final int siteId;
|
||||
final int userId;
|
||||
final int id;
|
||||
final String workName;
|
||||
final WorkRecordJsonData? jsonData;
|
||||
final String? imgUrl;
|
||||
|
||||
WorkRecordEntity({
|
||||
this.createBy,
|
||||
this.createTime,
|
||||
this.updateBy,
|
||||
this.updateTime,
|
||||
required this.delFlag,
|
||||
this.remark,
|
||||
required this.orgId,
|
||||
required this.siteId,
|
||||
required this.userId,
|
||||
required this.id,
|
||||
required this.workName,
|
||||
this.jsonData,
|
||||
this.imgUrl,
|
||||
});
|
||||
|
||||
factory WorkRecordEntity.fromXml(Map<String, dynamic> xmlData) {
|
||||
return WorkRecordEntity(
|
||||
createBy: xmlData['createBy'] as String?,
|
||||
createTime: xmlData['createTime'] as String?,
|
||||
updateBy: xmlData['updateBy'] as String?,
|
||||
updateTime: xmlData['updateTime'] as String?,
|
||||
delFlag: xmlData['delFlag'] == 'true',
|
||||
remark: xmlData['remark'] as String?,
|
||||
orgId: int.tryParse(xmlData['orgId']?.toString() ?? '0') ?? 0,
|
||||
siteId: int.tryParse(xmlData['siteId']?.toString() ?? '0') ?? 0,
|
||||
userId: int.tryParse(xmlData['userId']?.toString() ?? '0') ?? 0,
|
||||
id: int.tryParse(xmlData['id']?.toString() ?? '0') ?? 0,
|
||||
workName: xmlData['workName'] as String? ?? '',
|
||||
jsonData: xmlData['jsonData'] != null
|
||||
? WorkRecordJsonData.fromXml(
|
||||
xmlData['jsonData'] as Map<String, dynamic>,
|
||||
)
|
||||
: null,
|
||||
imgUrl: xmlData['imgUrl'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
factory WorkRecordEntity.fromJson(Map<String, dynamic> json) {
|
||||
return WorkRecordEntity(
|
||||
createBy: json['createBy'] as String?,
|
||||
createTime: json['createTime'] as String?,
|
||||
updateBy: json['updateBy'] as String?,
|
||||
updateTime: json['updateTime'] as String?,
|
||||
delFlag: json['delFlag'] == true || json['delFlag'] == 'true',
|
||||
remark: json['remark'] as String?,
|
||||
orgId: _parseInt(json['orgId']),
|
||||
siteId: _parseInt(json['siteId']),
|
||||
userId: _parseInt(json['userId']),
|
||||
id: _parseInt(json['id']),
|
||||
workName: json['workName'] as String? ?? '',
|
||||
jsonData: json['jsonData'] != null
|
||||
? WorkRecordJsonData.fromJson(
|
||||
json['jsonData'] as Map<String, dynamic>,
|
||||
)
|
||||
: null,
|
||||
imgUrl: json['imgUrl'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
static int _parseInt(dynamic value) {
|
||||
if (value == null) return 0;
|
||||
if (value is int) return value;
|
||||
if (value is num) return value.toInt();
|
||||
if (value is String) return int.tryParse(value) ?? 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// 工作记录JSON数据
|
||||
class WorkRecordJsonData {
|
||||
final String? name;
|
||||
final List<Map<String, double>>? path;
|
||||
final List<Map<String, double>>? outer;
|
||||
final String? img;
|
||||
final int? planModel;
|
||||
|
||||
WorkRecordJsonData({
|
||||
this.name,
|
||||
this.path,
|
||||
this.outer,
|
||||
this.img,
|
||||
this.planModel,
|
||||
});
|
||||
|
||||
factory WorkRecordJsonData.fromXml(Map<String, dynamic> xmlData) {
|
||||
return WorkRecordJsonData(
|
||||
name: xmlData['name'] as String?,
|
||||
path: _parsePathList(xmlData['path']),
|
||||
outer: _parseOuterList(xmlData['outer']),
|
||||
img: xmlData['img'] as String?,
|
||||
planModel: int.tryParse(xmlData['planModel']?.toString() ?? '0'),
|
||||
);
|
||||
}
|
||||
|
||||
factory WorkRecordJsonData.fromJson(Map<String, dynamic> json) {
|
||||
return WorkRecordJsonData(
|
||||
name: json['name'] as String?,
|
||||
path: _parsePathListJson(json['path']),
|
||||
outer: _parseOuterListJson(json['outer']),
|
||||
img: json['img'] as String?,
|
||||
planModel: (json['planModel'] as num?)?.toInt(),
|
||||
);
|
||||
}
|
||||
|
||||
static List<Map<String, double>>? _parsePathList(dynamic pathData) {
|
||||
if (pathData == null) return null;
|
||||
|
||||
// path 可能是 List 或 Map
|
||||
if (pathData is List) {
|
||||
return pathData.map((item) {
|
||||
if (item is Map) {
|
||||
return {
|
||||
'lat': double.tryParse(item['lat']?.toString() ?? '0') ?? 0.0,
|
||||
'lng': double.tryParse(item['lng']?.toString() ?? '0') ?? 0.0,
|
||||
};
|
||||
}
|
||||
return <String, double>{};
|
||||
}).toList();
|
||||
} else if (pathData is Map) {
|
||||
// 如果是单个 Map,检查是否包含 path 子节点
|
||||
if (pathData.containsKey('path')) {
|
||||
final pathList = pathData['path'];
|
||||
if (pathList is List) {
|
||||
return pathList.map((item) {
|
||||
if (item is Map) {
|
||||
return {
|
||||
'lat': double.tryParse(item['lat']?.toString() ?? '0') ?? 0.0,
|
||||
'lng': double.tryParse(item['lng']?.toString() ?? '0') ?? 0.0,
|
||||
};
|
||||
}
|
||||
return <String, double>{};
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
// 直接是单个 path 节点
|
||||
return [
|
||||
{
|
||||
'lat': double.tryParse(pathData['lat']?.toString() ?? '0') ?? 0.0,
|
||||
'lng': double.tryParse(pathData['lng']?.toString() ?? '0') ?? 0.0,
|
||||
},
|
||||
];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<Map<String, double>>? _parseOuterList(dynamic outerData) {
|
||||
if (outerData == null) return null;
|
||||
|
||||
// outer 可能是 List 或 Map
|
||||
if (outerData is List) {
|
||||
return outerData.map((item) {
|
||||
if (item is Map) {
|
||||
return {
|
||||
'lat': double.tryParse(item['lat']?.toString() ?? '0') ?? 0.0,
|
||||
'lng': double.tryParse(item['lng']?.toString() ?? '0') ?? 0.0,
|
||||
};
|
||||
}
|
||||
return <String, double>{};
|
||||
}).toList();
|
||||
} else if (outerData is Map) {
|
||||
// 如果是单个 Map,检查是否包含 outer 子节点
|
||||
if (outerData.containsKey('outer')) {
|
||||
final outerList = outerData['outer'];
|
||||
if (outerList is List) {
|
||||
return outerList.map((item) {
|
||||
if (item is Map) {
|
||||
return {
|
||||
'lat': double.tryParse(item['lat']?.toString() ?? '0') ?? 0.0,
|
||||
'lng': double.tryParse(item['lng']?.toString() ?? '0') ?? 0.0,
|
||||
};
|
||||
}
|
||||
return <String, double>{};
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
// 直接是单个 outer 节点
|
||||
return [
|
||||
{
|
||||
'lat': double.tryParse(outerData['lat']?.toString() ?? '0') ?? 0.0,
|
||||
'lng': double.tryParse(outerData['lng']?.toString() ?? '0') ?? 0.0,
|
||||
},
|
||||
];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// JSON格式解析path
|
||||
static List<Map<String, double>>? _parsePathListJson(dynamic pathData) {
|
||||
if (pathData == null) return null;
|
||||
if (pathData is List) {
|
||||
return pathData.map((item) {
|
||||
if (item is Map) {
|
||||
return {
|
||||
'lat': (item['lat'] as num?)?.toDouble() ?? 0.0,
|
||||
'lng': (item['lng'] as num?)?.toDouble() ?? 0.0,
|
||||
};
|
||||
}
|
||||
return <String, double>{};
|
||||
}).toList();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// JSON格式解析outer
|
||||
static List<Map<String, double>>? _parseOuterListJson(dynamic outerData) {
|
||||
if (outerData == null) return null;
|
||||
if (outerData is List) {
|
||||
return outerData.map((item) {
|
||||
if (item is Map) {
|
||||
return {
|
||||
'lat': (item['lat'] as num?)?.toDouble() ?? 0.0,
|
||||
'lng': (item['lng'] as num?)?.toDouble() ?? 0.0,
|
||||
};
|
||||
}
|
||||
return <String, double>{};
|
||||
}).toList();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import 'dart:math';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
import 'package:xml/xml.dart';
|
||||
|
||||
import '../../../../core/di/injection.dart';
|
||||
import '../../../../core/storage/user_storage.dart';
|
||||
@@ -9,10 +10,12 @@ import '../../domain/repositories/path_repository.dart';
|
||||
import '../datasources/path_http_datasource.dart';
|
||||
import '../models/device_add_path_point_model.dart';
|
||||
import '../models/device_work_area_param_model.dart';
|
||||
import '../models/work_record_entity.dart';
|
||||
|
||||
class PathRepositoryImpl implements PathRepository {
|
||||
final PathHttpDatasource _datasource;
|
||||
PathRepositoryImpl({required PathHttpDatasource datasource}) : _datasource = datasource;
|
||||
PathRepositoryImpl({required PathHttpDatasource datasource})
|
||||
: _datasource = datasource;
|
||||
// 生成路径
|
||||
@override
|
||||
Future<List<DeviceAddPathPointModel>> generatePath({
|
||||
@@ -38,10 +41,18 @@ class PathRepositoryImpl implements PathRepository {
|
||||
|
||||
// 保存工作记录
|
||||
@override
|
||||
Future<Map<String, dynamic>> saveWorkRecord({required String workName, required String userId, required String jsonData}) async {
|
||||
Future<Map<String, dynamic>> saveWorkRecord({
|
||||
required String workName,
|
||||
required String userId,
|
||||
required String jsonData,
|
||||
}) async {
|
||||
final url = Uri.parse('https://serviceri.satabot.com/iot/workRecord/add');
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final body = jsonEncode({'workName': workName, 'userId': userId, 'jsonData': jsonData});
|
||||
final body = jsonEncode({
|
||||
'workName': workName,
|
||||
'userId': userId,
|
||||
'jsonData': jsonData,
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await http.post(url, headers: headers, body: body);
|
||||
@@ -57,7 +68,9 @@ class PathRepositoryImpl implements PathRepository {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Map<String, dynamic>>> getWorkRecord({required String userId}) async {
|
||||
Future<List<Map<String, dynamic>>> getWorkRecord({
|
||||
required String userId,
|
||||
}) async {
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final url = Uri.parse(
|
||||
'https://serviceri.satabot.com/iot/workRecord/selectByUserId',
|
||||
@@ -73,7 +86,9 @@ class PathRepositoryImpl implements PathRepository {
|
||||
throw Exception('API error: ${data['msg'] ?? 'Unknown'}');
|
||||
}
|
||||
} else {
|
||||
throw Exception('HTTP ${response.statusCode}: ${response.reasonPhrase}');
|
||||
throw Exception(
|
||||
'HTTP ${response.statusCode}: ${response.reasonPhrase}',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
throw Exception('Network error in getWorkRecord: $e');
|
||||
@@ -81,11 +96,16 @@ class PathRepositoryImpl implements PathRepository {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> deleteWorkRecord({required String workName}) async {
|
||||
Future<Map<String, dynamic>> deleteWorkRecord({
|
||||
required String workName,
|
||||
}) async {
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final url = Uri.parse(
|
||||
'https://serviceri.satabot.com/iot/workRecord/deleteByWorkName',
|
||||
).replace(queryParameters: {'workName': workName, '_t': timestamp.toString()});
|
||||
final url =
|
||||
Uri.parse(
|
||||
'https://serviceri.satabot.com/iot/workRecord/deleteByWorkName',
|
||||
).replace(
|
||||
queryParameters: {'workName': workName, '_t': timestamp.toString()},
|
||||
);
|
||||
|
||||
try {
|
||||
final response = await http.get(url);
|
||||
@@ -94,7 +114,9 @@ class PathRepositoryImpl implements PathRepository {
|
||||
if (response.statusCode == 200 && data['code'] == 200) {
|
||||
return data; // 返回 {"code": 200, "msg": "删除成功"}
|
||||
} else {
|
||||
throw Exception('Delete failed: ${data['msg'] ?? response.reasonPhrase}');
|
||||
throw Exception(
|
||||
'Delete failed: ${data['msg'] ?? response.reasonPhrase}',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
throw Exception('Network error in deleteWorkRecord: $e');
|
||||
@@ -103,11 +125,16 @@ class PathRepositoryImpl implements PathRepository {
|
||||
|
||||
/// 选择工作记录
|
||||
@override
|
||||
Future<List<Map<String, dynamic>>> selectWorkRecordByName({required String workName}) async {
|
||||
Future<List<Map<String, dynamic>>> selectWorkRecordByName({
|
||||
required String workName,
|
||||
}) async {
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final url = Uri.parse(
|
||||
'https://serviceri.satabot.com/iot/workRecord/selectByWorkName',
|
||||
).replace(queryParameters: {'workName': workName, '_t': timestamp.toString()});
|
||||
final url =
|
||||
Uri.parse(
|
||||
'https://serviceri.satabot.com/iot/workRecord/selectByWorkName',
|
||||
).replace(
|
||||
queryParameters: {'workName': workName, '_t': timestamp.toString()},
|
||||
);
|
||||
|
||||
try {
|
||||
final response = await http.get(url);
|
||||
@@ -131,7 +158,9 @@ class PathRepositoryImpl implements PathRepository {
|
||||
} else if (rawData is Map) {
|
||||
records = [Map<String, dynamic>.from(rawData)];
|
||||
} else {
|
||||
throw Exception('Unexpected data type for "data": ${rawData.runtimeType}');
|
||||
throw Exception(
|
||||
'Unexpected data type for "data": ${rawData.runtimeType}',
|
||||
);
|
||||
}
|
||||
|
||||
return records;
|
||||
@@ -139,10 +168,228 @@ class PathRepositoryImpl implements PathRepository {
|
||||
throw Exception('API error: ${data['msg'] ?? 'Unknown'}');
|
||||
}
|
||||
} else {
|
||||
throw Exception('HTTP ${response.statusCode}: ${response.reasonPhrase}');
|
||||
throw Exception(
|
||||
'HTTP ${response.statusCode}: ${response.reasonPhrase}',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
throw Exception('Network error in selectWorkRecordByName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// 根据场站ID查询工作记录列表(XML格式)
|
||||
@override
|
||||
Future<List<WorkRecordEntity>> getWorkRecordsBySiteId({
|
||||
required int siteId,
|
||||
}) async {
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final url =
|
||||
Uri.parse(
|
||||
'http://1.95.137.212:59015/iot/workRecord/selectBySiteId',
|
||||
).replace(
|
||||
queryParameters: {
|
||||
'siteId': siteId.toString(),
|
||||
'_t': timestamp.toString(),
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
final response = await http.get(
|
||||
url,
|
||||
headers: {'Accept': 'application/xml, text/xml, */*'},
|
||||
);
|
||||
print('[XML接口] 响应状态码: ${response.statusCode}');
|
||||
print('[XML接口] 响应内容长度: ${response.body.length}');
|
||||
print('[XML接口] Content-Type: ${response.headers['content-type']}');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// 打印前200字符确认格式
|
||||
final preview = response.body.length > 200
|
||||
? response.body.substring(0, 200)
|
||||
: response.body;
|
||||
print('[XML接口] 响应开头: $preview');
|
||||
|
||||
// 判断是JSON还是XML格式
|
||||
final trimmed = response.body.trim();
|
||||
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
|
||||
print('[XML接口] 检测到JSON格式,使用JSON解析');
|
||||
return _parseJsonResponse(response.body);
|
||||
} else {
|
||||
print('[XML接口] 检测到XML格式,使用XML解析');
|
||||
return _parseXmlResponse(response.body);
|
||||
}
|
||||
} else {
|
||||
throw Exception(
|
||||
'HTTP ${response.statusCode}: ${response.reasonPhrase}',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
print('[XML接口] 错误: $e');
|
||||
throw Exception('Network error in getWorkRecordsBySiteId: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析JSON格式响应
|
||||
Future<List<WorkRecordEntity>> _parseJsonResponse(String body) async {
|
||||
final data = jsonDecode(body) as Map<String, dynamic>;
|
||||
|
||||
if (data['code'] != 200) {
|
||||
throw Exception('API error: ${data['msg'] ?? 'Unknown'}');
|
||||
}
|
||||
|
||||
final recordsData = data['data'];
|
||||
if (recordsData == null) return [];
|
||||
|
||||
final List<WorkRecordEntity> records = [];
|
||||
|
||||
if (recordsData is List) {
|
||||
for (final item in recordsData) {
|
||||
if (item is Map<String, dynamic>) {
|
||||
records.add(WorkRecordEntity.fromJson(item));
|
||||
}
|
||||
}
|
||||
} else if (recordsData is Map<String, dynamic>) {
|
||||
records.add(WorkRecordEntity.fromJson(recordsData));
|
||||
}
|
||||
|
||||
print('[XML接口] 最终解析记录数: ${records.length}');
|
||||
return records;
|
||||
}
|
||||
|
||||
/// 解析XML格式响应
|
||||
Future<List<WorkRecordEntity>> _parseXmlResponse(String body) async {
|
||||
// 用更宽松的正则检查响应码(支持命名空间前缀)
|
||||
final codeMatch = RegExp(
|
||||
r'<\w*:?code[^>]*>(\d+)</\w*:?code>',
|
||||
).firstMatch(body);
|
||||
final code = codeMatch?.group(1);
|
||||
print('[XML接口] code: $code');
|
||||
|
||||
if (code != '200') {
|
||||
final msgMatch = RegExp(
|
||||
r'<\w*:?msg[^>]*>(.*?)</\w*:?msg>',
|
||||
).firstMatch(body);
|
||||
throw Exception('API error: ${msgMatch?.group(1) ?? 'Unknown'}');
|
||||
}
|
||||
|
||||
// 使用正则表达式提取所有<data>...</data>节点
|
||||
// 使用非贪婪匹配,确保每个data节点独立提取
|
||||
final dataRegex = RegExp(r'<data>([\s\S]*?)</data>');
|
||||
final dataMatches = dataRegex.allMatches(body);
|
||||
print('[XML接口] 找到data节点数量: ${dataMatches.length}');
|
||||
|
||||
// 解析所有工作记录
|
||||
final List<WorkRecordEntity> records = [];
|
||||
|
||||
for (int i = 0; i < dataMatches.length; i++) {
|
||||
final match = dataMatches.elementAt(i);
|
||||
final dataContent = match.group(1)!; // 获取<data>和</data>之间的内容
|
||||
|
||||
try {
|
||||
// 将提取的内容包装成完整XML进行解析
|
||||
final wrappedXml = '<root>$dataContent</root>';
|
||||
final document = XmlDocument.parse(wrappedXml);
|
||||
final recordElement = document.rootElement;
|
||||
|
||||
final recordData = _parseXmlRecord(recordElement);
|
||||
print(
|
||||
'[XML接口] data[$i] 解析结果: workName=${recordData['workName']}, id=${recordData['id']}, imgUrl=${recordData['imgUrl']}',
|
||||
);
|
||||
|
||||
records.add(WorkRecordEntity.fromXml(recordData));
|
||||
} catch (e) {
|
||||
print('[XML接口] 解析单个data节点失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
print('[XML接口] 最终解析记录数: ${records.length}');
|
||||
return records;
|
||||
}
|
||||
|
||||
/// 解析XML工作记录节点
|
||||
Map<String, dynamic> _parseXmlRecord(XmlElement recordElement) {
|
||||
final Map<String, dynamic> result = {};
|
||||
|
||||
print('[XML解析] 开始解析节点,子元素数量: ${recordElement.childElements.length}');
|
||||
|
||||
for (final child in recordElement.childElements) {
|
||||
final tagName = child.name.local;
|
||||
final innerText = child.innerText.trim();
|
||||
|
||||
print(
|
||||
'[XML解析] 标签: $tagName, 值: ${innerText.length > 50 ? innerText.substring(0, 50) + '...' : innerText}',
|
||||
);
|
||||
|
||||
// 特殊处理jsonData节点(包含嵌套结构)
|
||||
if (tagName == 'jsonData') {
|
||||
result['jsonData'] = _parseJsonDataNode(child);
|
||||
} else {
|
||||
// 普通节点直接取值
|
||||
result[tagName] = innerText;
|
||||
}
|
||||
}
|
||||
|
||||
print('[XML解析] 解析完成,结果keys: ${result.keys.toList()}');
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 解析jsonData节点
|
||||
Map<String, dynamic> _parseJsonDataNode(XmlElement jsonDataElement) {
|
||||
final Map<String, dynamic> result = {};
|
||||
|
||||
for (final child in jsonDataElement.childElements) {
|
||||
final tagName = child.name.local;
|
||||
|
||||
if (tagName == 'path' || tagName == 'outer') {
|
||||
// path和outer可能包含嵌套的path/outer节点
|
||||
result[tagName] = _parseCoordinateList(child, tagName);
|
||||
} else {
|
||||
// 普通字段(name, img, planModel等)
|
||||
result[tagName] = child.innerText.trim();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 解析坐标列表(path或outer)
|
||||
List<Map<String, double>> _parseCoordinateList(
|
||||
XmlElement element,
|
||||
String tagName,
|
||||
) {
|
||||
final List<Map<String, double>> coordinates = [];
|
||||
|
||||
// 检查是否有嵌套的同名节点
|
||||
final nestedElements = element.childElements
|
||||
.where((e) => e.name.local == tagName)
|
||||
.toList();
|
||||
|
||||
if (nestedElements.isNotEmpty) {
|
||||
// 有嵌套结构:outer > outer > {lat, lng}
|
||||
for (final nestedElement in nestedElements) {
|
||||
final latElement = nestedElement.getElement('lat');
|
||||
final lngElement = nestedElement.getElement('lng');
|
||||
|
||||
if (latElement != null && lngElement != null) {
|
||||
coordinates.add({
|
||||
'lat': double.tryParse(latElement.innerText.trim()) ?? 0.0,
|
||||
'lng': double.tryParse(lngElement.innerText.trim()) ?? 0.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 直接包含lat/lng节点
|
||||
final latElement = element.getElement('lat');
|
||||
final lngElement = element.getElement('lng');
|
||||
|
||||
if (latElement != null && lngElement != null) {
|
||||
coordinates.add({
|
||||
'lat': double.tryParse(latElement.innerText.trim()) ?? 0.0,
|
||||
'lng': double.tryParse(lngElement.innerText.trim()) ?? 0.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return coordinates;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user