显示周边加氢站
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 去除高德默认的 label 边框和背景 */
|
/* 去除高德默认的 label 边框 and 背景 */
|
||||||
.amap-marker-label {
|
.amap-marker-label {
|
||||||
border: none !important;
|
border: none !important;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
@@ -221,6 +221,7 @@
|
|||||||
var currentLat, currentLng;
|
var currentLat, currentLng;
|
||||||
var isTruckMode = false;
|
var isTruckMode = false;
|
||||||
var isInitialLocationSet = false;
|
var isInitialLocationSet = false;
|
||||||
|
var stationMarkers = []; // 存储所有站点的标记
|
||||||
|
|
||||||
|
|
||||||
function initMap() {
|
function initMap() {
|
||||||
@@ -336,6 +337,8 @@
|
|||||||
fetchStationInfo(addressComponent.province, addressComponent.city,
|
fetchStationInfo(addressComponent.province, addressComponent.city,
|
||||||
addressComponent.district, lat, lng);
|
addressComponent.district, lat, lng);
|
||||||
|
|
||||||
|
fetchStationInfoList(lat, lng);
|
||||||
|
|
||||||
// 策略1: 优先使用最近的、类型合适的POI的名称
|
// 策略1: 优先使用最近的、类型合适的POI的名称
|
||||||
if (pois && pois.length > 0) {
|
if (pois && pois.length > 0) {
|
||||||
// 查找第一个类型不是“商务住宅”或“地名地址信息”的POI,这类POI通常是具体的建筑或地点名
|
// 查找第一个类型不是“商务住宅”或“地名地址信息”的POI,这类POI通常是具体的建筑或地点名
|
||||||
@@ -397,7 +400,6 @@
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
// "asoco-token": "e28eada8-4611-4dc2-a942-0122e52f52da"
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
province: province,
|
province: province,
|
||||||
@@ -437,6 +439,73 @@
|
|||||||
.catch(err => console.error('JS->:获取站点信息失败:', err));
|
.catch(err => console.error('JS->:获取站点信息失败:', err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取站点列表
|
||||||
|
*/
|
||||||
|
function fetchStationInfoList(lat, lng) {
|
||||||
|
fetch('https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
longitude: lng,
|
||||||
|
latitude: lat,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('网络响应错误: ' + response.status);
|
||||||
|
}
|
||||||
|
return response.json(); // 解析 JSON
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
console.log("JS->:2 接口完整返回:", JSON.stringify(res));
|
||||||
|
if (res.code === 0 && res.data && Array.isArray(res.data)) {
|
||||||
|
// 1. 清除旧的站点标记
|
||||||
|
stationMarkers.forEach(m => m.setMap(null));
|
||||||
|
stationMarkers = [];
|
||||||
|
|
||||||
|
// 2. 循环标记所有加氢站
|
||||||
|
res.data.forEach(station => {
|
||||||
|
var stationIcon = new AMap.Icon({
|
||||||
|
size: new AMap.Size(32, 32),
|
||||||
|
image: 'ic_tag.png',
|
||||||
|
imageSize: new AMap.Size(32, 32)
|
||||||
|
});
|
||||||
|
|
||||||
|
var sMarker = new AMap.Marker({
|
||||||
|
map: map,
|
||||||
|
position: [station.longitude, station.latitude],
|
||||||
|
icon: stationIcon,
|
||||||
|
offset: new AMap.Pixel(-16, -32),
|
||||||
|
title: station.name,
|
||||||
|
label: {
|
||||||
|
content: '<div class="custom-bubble">' + station.name + '</div>',
|
||||||
|
direction: 'top'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. 绑定点击事件:选中即为目的地,并开始规划
|
||||||
|
sMarker.on('click', function() {
|
||||||
|
document.getElementById('endInput').value = station.address || station.name;
|
||||||
|
// 更新当前的 destMarker (如果需要)
|
||||||
|
if (destMarker) destMarker.setMap(null);
|
||||||
|
destMarker = sMarker;
|
||||||
|
|
||||||
|
startRouteSearch();
|
||||||
|
});
|
||||||
|
|
||||||
|
stationMarkers.push(sMarker);
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log("JS->: 业务报错或无数据:", res.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => console.error('JS->:获取站点信息失败:', err));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 地理编码并在地图标记终点
|
* 地理编码并在地图标记终点
|
||||||
*/
|
*/
|
||||||
@@ -447,7 +516,6 @@
|
|||||||
if (destMarker) destMarker.setMap(null);
|
if (destMarker) destMarker.setMap(null);
|
||||||
|
|
||||||
// 2. 创建自定义图标
|
// 2. 创建自定义图标
|
||||||
// 假设图标大小为 32x32,你可以根据实际图片尺寸调整 Size
|
|
||||||
var destIcon = new AMap.Icon({
|
var destIcon = new AMap.Icon({
|
||||||
size: new AMap.Size(32, 32), // 图标尺寸
|
size: new AMap.Size(32, 32), // 图标尺寸
|
||||||
image: 'ic_tag.png', // 本地图片路径
|
image: 'ic_tag.png', // 本地图片路径
|
||||||
@@ -459,8 +527,6 @@
|
|||||||
map: map,
|
map: map,
|
||||||
position: [longitude, latitude],
|
position: [longitude, latitude],
|
||||||
icon: destIcon, // 使用自定义图标
|
icon: destIcon, // 使用自定义图标
|
||||||
// 偏移量:如果图标底部中心是尖角,offset 设为宽的一半的负数,高度的负数
|
|
||||||
// 这样能确保图片的底部尖端指向地图上的精确位置
|
|
||||||
offset: new AMap.Pixel(-16, -32),
|
offset: new AMap.Pixel(-16, -32),
|
||||||
title: name,
|
title: name,
|
||||||
label: {
|
label: {
|
||||||
@@ -469,17 +535,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 4. 打印调试信息
|
console.log("JS->: 终点标记已添加", address);
|
||||||
console.log("JS->: 终点标记已添加", address, loc.toString());
|
|
||||||
|
|
||||||
// 5. 自动调整视野包含起点和终点
|
|
||||||
// if (marker) {
|
|
||||||
// // 如果起点标志已存在,缩放地图以展示两者
|
|
||||||
// map.setFitView([marker, destMarker], false, [60, 60, 60, 60]);
|
|
||||||
// } else {
|
|
||||||
// // 如果没有起点,直接跳到终点
|
|
||||||
// map.setCenter(loc);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -523,40 +579,34 @@
|
|||||||
document.getElementById('startInput').blur();
|
document.getElementById('startInput').blur();
|
||||||
document.getElementById('endInput').blur();
|
document.getElementById('endInput').blur();
|
||||||
|
|
||||||
// --- 构造路径规划的点 (使用数组方式,更灵活) ---
|
// --- 构造路径规划的点 ---
|
||||||
var points = [];
|
var points = [];
|
||||||
|
|
||||||
// 1. 处理起点逻辑
|
// 1. 处理起点逻辑
|
||||||
// 如果输入框是空的,或者写着 "我的位置",则使用 GPS 坐标
|
if (!startKw || startKw === '我的位置' || startKw.includes('当前位置')) {
|
||||||
if (!startKw || startKw === '我的位置') {
|
|
||||||
if (!currentLng || !currentLat) {
|
if (!currentLng || !currentLat) {
|
||||||
// 如果还没获取到定位
|
|
||||||
if (window.flutter_inappwebview) {
|
if (window.flutter_inappwebview) {
|
||||||
window.flutter_inappwebview.callHandler('requestLocation');
|
window.flutter_inappwebview.callHandler('requestLocation');
|
||||||
}
|
}
|
||||||
alert("正在获取定位,请稍后...");
|
alert("正在获取定位,请稍后...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 使用精准坐标对象 (避免高德去猜 '我的位置' 关键词)
|
|
||||||
points.push({
|
points.push({
|
||||||
keyword: '我的位置', // 用于显示的名字
|
keyword: '我的位置',
|
||||||
location: new AMap.LngLat(currentLng, currentLat) // 实际导航用的坐标
|
location: new AMap.LngLat(currentLng, currentLat)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 如果用户手动输入了地点 (例如 "北京南站")
|
|
||||||
// 直接存入关键词,让高德自己去搜
|
|
||||||
points.push({
|
points.push({
|
||||||
keyword: startKw
|
keyword: startKw
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 处理终点逻辑 (通常是关键词)
|
// 2. 处理终点逻辑
|
||||||
points.push({
|
points.push({
|
||||||
keyword: endKw
|
keyword: endKw
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3. 发起搜索
|
// 3. 发起搜索
|
||||||
// points 数组里现在是一个起点对象和一个终点对象
|
|
||||||
driving.search(points, function (status, result) {
|
driving.search(points, function (status, result) {
|
||||||
if (status === 'complete') {
|
if (status === 'complete') {
|
||||||
console.log('JS: 规划成功');
|
console.log('JS: 规划成功');
|
||||||
|
|||||||
150
ln_jq_app/lib/pages/b_page/history/controller.dart
Normal file
150
ln_jq_app/lib/pages/b_page/history/controller.dart
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:getx_scaffold/getx_scaffold.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:ln_jq_app/common/model/base_model.dart';
|
||||||
|
import 'package:ln_jq_app/pages/b_page/site/controller.dart'; // Reuse ReservationModel
|
||||||
|
|
||||||
|
class HistoryController extends GetxController with BaseControllerMixin {
|
||||||
|
@override
|
||||||
|
String get builderId => 'history';
|
||||||
|
|
||||||
|
// --- 定义 API 需要的日期格式化器 ---
|
||||||
|
final DateFormat _apiDateFormat = DateFormat('yyyy-MM-dd');
|
||||||
|
|
||||||
|
// 默认查询最近7天
|
||||||
|
final Rx<DateTime> startDate = DateTime.now().subtract(const Duration(days: 7)).obs;
|
||||||
|
final Rx<DateTime> endDate = DateTime.now().obs;
|
||||||
|
final TextEditingController plateNumberController = TextEditingController();
|
||||||
|
|
||||||
|
final RxString totalHydrogen = '0'.obs;
|
||||||
|
final RxString totalCompletions = '0'.obs;
|
||||||
|
|
||||||
|
final RxList<ReservationModel> historyList = <ReservationModel>[].obs;
|
||||||
|
final RxBool isLoading = true.obs;
|
||||||
|
final RxBool hasData = false.obs;
|
||||||
|
|
||||||
|
String get formattedStartDate => DateFormat('yyyy/MM/dd').format(startDate.value);
|
||||||
|
String get formattedEndDate => DateFormat('yyyy/MM/dd').format(endDate.value);
|
||||||
|
|
||||||
|
String stationName = "";
|
||||||
|
|
||||||
|
final Map<String, String> statusOptions = {
|
||||||
|
'': '全部',
|
||||||
|
'0': '待加氢',
|
||||||
|
'1': '已加氢',
|
||||||
|
'2': '未加氢',
|
||||||
|
'5': '拒绝加氢',
|
||||||
|
};
|
||||||
|
|
||||||
|
final RxString selectedStatus = ''.obs;
|
||||||
|
final RxString selectedDateType = ''.obs; // week, month, three_month
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
final args = Get.arguments as Map<String, dynamic>;
|
||||||
|
stationName = args['stationName'] as String? ?? "";
|
||||||
|
refreshData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void refreshData() {
|
||||||
|
getAllOrderCounts();
|
||||||
|
fetchHistoryData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getAllOrderCounts() async {
|
||||||
|
var response = await HttpService.to.post(
|
||||||
|
"appointment/orderAddHyd/getAllOrderCounts",
|
||||||
|
data: {
|
||||||
|
/*'startTime': _apiDateFormat.format(startDate.value),
|
||||||
|
'endTime': _apiDateFormat.format(endDate.value),*/
|
||||||
|
'plateNumber': plateNumberController.text,
|
||||||
|
'stationName': stationName,
|
||||||
|
"status": selectedStatus.value,
|
||||||
|
"dateType": selectedDateType.value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (response == null || response.data == null) {
|
||||||
|
totalHydrogen.value = '0';
|
||||||
|
totalCompletions.value = '0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final baseModel = BaseModel<dynamic>.fromJson(response.data);
|
||||||
|
final dataMap = baseModel.data as Map<String, dynamic>;
|
||||||
|
totalHydrogen.value = '${dataMap['totalAddAmount'] ?? 0}';
|
||||||
|
totalCompletions.value = '${dataMap['orderCompleteCount'] ?? 0}';
|
||||||
|
} catch (e) {
|
||||||
|
totalHydrogen.value = '0';
|
||||||
|
totalCompletions.value = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> fetchHistoryData() async {
|
||||||
|
isLoading.value = true;
|
||||||
|
updateUi();
|
||||||
|
|
||||||
|
try {
|
||||||
|
var response = await HttpService.to.post(
|
||||||
|
"appointment/orderAddHyd/sitOrderPage",
|
||||||
|
data: {
|
||||||
|
/*'startTime': _apiDateFormat.format(startDate.value),
|
||||||
|
'endTime': _apiDateFormat.format(endDate.value),*/
|
||||||
|
'plateNumber': plateNumberController.text,
|
||||||
|
'pageNum': 1,
|
||||||
|
'pageSize': 50,
|
||||||
|
'stationName': stationName,
|
||||||
|
"status": selectedStatus.value,
|
||||||
|
"dateType": selectedDateType.value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response == null || response.data == null) {
|
||||||
|
_resetData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final baseModel = BaseModel<dynamic>.fromJson(response.data);
|
||||||
|
if (baseModel.code == 0 && baseModel.data != null) {
|
||||||
|
final dataMap = baseModel.data as Map<String, dynamic>;
|
||||||
|
final List<dynamic> listFromServer = dataMap['records'] ?? [];
|
||||||
|
historyList.assignAll(
|
||||||
|
listFromServer
|
||||||
|
.map((item) => ReservationModel.fromJson(item as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
hasData.value = historyList.isNotEmpty;
|
||||||
|
} else {
|
||||||
|
_resetData();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_resetData();
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
updateUi();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _resetData() {
|
||||||
|
historyList.clear();
|
||||||
|
hasData.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onStatusSelected(String status) {
|
||||||
|
if (selectedStatus.value == status) return;
|
||||||
|
selectedStatus.value = status;
|
||||||
|
refreshData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDateTypeSelected(String type) {
|
||||||
|
selectedDateType.value = type;
|
||||||
|
refreshData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {
|
||||||
|
plateNumberController.dispose();
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -153,7 +153,6 @@ class MallPage extends GetView<MallController> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 12.h),
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:getx_scaffold/common/index.dart';
|
import 'package:getx_scaffold/common/index.dart';
|
||||||
import 'package:ln_jq_app/common/model/base_model.dart';
|
import 'package:ln_jq_app/common/model/base_model.dart';
|
||||||
|
import 'package:ln_jq_app/common/styles/theme.dart';
|
||||||
import 'package:ln_jq_app/pages/c_page/reservation/controller.dart';
|
import 'package:ln_jq_app/pages/c_page/reservation/controller.dart';
|
||||||
import 'package:ln_jq_app/pages/c_page/reservation_edit/controller.dart';
|
import 'package:ln_jq_app/pages/c_page/reservation_edit/controller.dart';
|
||||||
import 'package:ln_jq_app/pages/c_page/reservation_edit/view.dart';
|
import 'package:ln_jq_app/pages/c_page/reservation_edit/view.dart';
|
||||||
@@ -203,14 +204,14 @@ class _ReservationListBottomSheetState extends State<ReservationListBottomSheet>
|
|||||||
},
|
},
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
side: BorderSide(color: Colors.grey.shade400), // 灰色边框
|
side: BorderSide(color: Colors.grey.shade400),
|
||||||
shape: const StadiumBorder(), // 胶囊形状
|
shape: const StadiumBorder(),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'取消预约',
|
'取消预约',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.grey.shade600,
|
color: Colors.grey.shade600,
|
||||||
fontSize: 12,
|
fontSize: 11.sp,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -241,13 +242,13 @@ class _ReservationListBottomSheetState extends State<ReservationListBottomSheet>
|
|||||||
},
|
},
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
side: const BorderSide(color: Colors.blue), // 蓝色边框
|
side: BorderSide(color: AppTheme.themeColor),
|
||||||
shape: const StadiumBorder(),
|
shape: const StadiumBorder(),
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
),
|
),
|
||||||
child: const Text(
|
child: Text(
|
||||||
'修改',
|
'修改',
|
||||||
style: TextStyle(color: Colors.blue, fontSize: 12),
|
style: TextStyle(color: AppTheme.themeColor, fontSize: 11.sp),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user