优化轮播图 发送完成信号

This commit is contained in:
mmc
2026-03-12 20:04:18 +08:00
parent a0df048cb5
commit 00c5e736bd
7 changed files with 74 additions and 75 deletions

BIN
assets/images/carousel1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
assets/images/carousel2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
assets/images/carousel3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

View File

@@ -75,19 +75,10 @@ class _BannerCarouselState extends State<BannerCarousel> {
margin: EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
image: DecorationImage(image: NetworkImage(item.image), fit: BoxFit.cover),
image: DecorationImage(image: AssetImage(item.image), fit: BoxFit.cover),
),
child: Stack(
children: [
Positioned(
top: 12,
right: 12,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(color: Colors.black.withOpacity(0.5), borderRadius: BorderRadius.circular(4)),
child: Text('了解我们', style: TextStyle(color: Colors.white, fontSize: 14)),
),
),
Positioned(
left: 12,
bottom: 12,
@@ -117,6 +108,15 @@ class _BannerCarouselState extends State<BannerCarousel> {
}),
),
),
Positioned(
top: 12,
right: 24,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(color: Colors.black.withOpacity(0.5), borderRadius: BorderRadius.circular(4)),
child: Text('了解我们', style: TextStyle(color: Colors.white, fontSize: 14)),
),
),
],
),
);

View File

@@ -18,14 +18,11 @@ class NetMessageDispatcher {
// 🔥 修改:使用回调函数获取 AppState
final Function? getAppState;
NetMessageDispatcher(this.tcpClient, this.routePlanningRepository, this._pathPlanningService, {this.getAppState});
/// 过滤特定指令的流
Stream<RawPacket> onCommand(int commandCode) {
return tcpClient.packetStream.where((p) => p.command == commandCode);
}
/// 示例解析方法:将 0x02 指令解析为 String
@@ -42,7 +39,7 @@ class NetMessageDispatcher {
return ''; // 返回空字符串,避免流中断
}
});
/* ///return onCommand(0x02).map((p) => utf8.decode(p.payload));*/
/* ///return onCommand(0x02).map((p) => utf8.decode(p.payload));*/
}
/// 示例解析方法:将 0x12 指令解析为 JSON 并转为模型
@@ -52,13 +49,13 @@ class NetMessageDispatcher {
//监听路径规划的开始作业的指令的应答
// if (data[0] == (byte) 0xAB && data[1] == (byte) 0xAA && data[2] == (byte) 0x01) {
// System.out.println("=====下位机回复成功=====" + data[0] + " " + data[1] + " " + data[2] + " " + data[3] + " " +
// data[4] + " " + data[5] + " " + data[6] + " " + data[7] + " " + data[8] + " " + data[9]);
// if (data[5] == (byte) 0x01) {
// Point point = new Point();
// //发送下一个指令
// }
// if (data[0] == (byte) 0xAB && data[1] == (byte) 0xAA && data[2] == (byte) 0x01) {
// System.out.println("=====下位机回复成功=====" + data[0] + " " + data[1] + " " + data[2] + " " + data[3] + " " +
// data[4] + " " + data[5] + " " + data[6] + " " + data[7] + " " + data[8] + " " + data[9]);
// if (data[5] == (byte) 0x01) {
// Point point = new Point();
// //发送下一个指令
// }
/// 监听路径规划的开始作业指令的应答 (0x01 指令)
/// 协议格式:AB AA 01 [DATA] CRC(2) AA AB
@@ -83,39 +80,39 @@ class NetMessageDispatcher {
0xAB, 0xAA, 0x01,
...packet.payload,
0x00, 0x00, // CRC 占位
0xAA, 0xAB
0xAA, 0xAB,
];
// 验证头部协议
if (fullData[0] == 0xAB &&
fullData[1] == 0xAA &&
fullData[2] == 0x01) {
if (fullData[0] == 0xAB && fullData[1] == 0xAA && fullData[2] == 0x01) {
debugPrint('[Dispatcher] 下位机回复成功 - 完整数据包:${fullData.join(" ")}');
// 检查状态位 (索引 5 对应 payload 的第 2 个字节)
if (fullData.length > 5 && fullData[5] == 0x01) {
debugPrint('✅ [Dispatcher] 状态位验证通过:0x01 - 可以发送下一个指令');
///取全局的路径规划发送实体 queue
/// 发送下一个指令 移除上一条数据
var queue = _pathPlanningService.getQueue();
var queue = _pathPlanningService.getQueue();
///更新完成jwd
var deviceAddPathPointModel = queue.first;
devicesCubit.setArrivedLocation(
deviceAddPathPointModel.latitude,
deviceAddPathPointModel.longitude
);
devicesCubit.setArrivedLocation(deviceAddPathPointModel.latitude, deviceAddPathPointModel.longitude);
//去除上一条数据
queue.removeFirst();
/// _pathPlanningService.updateQueue(queue as List<DeviceAddPathPointModel>);
_pathPlanningService.updateQueue(queue.toList());
debugPrint('📡 [Dispatcher] 准备触发下一个路径点发送,队列剩余:${queue.length}');
///如果还剩0个数据 就停止发送
if (queue.length==0) {
if (queue.length == 0) {
debugPrint('⚠️ [Dispatcher] 队列已空,停止发送');
// final devicesCubit = sl<DevicesCubit>();
// final devicesCubit = sl<DevicesCubit>();
devicesCubit.finishWork();
Future.delayed(Duration(seconds: 1), () {
devicesCubit.resetWorkStatus();
});
return false;
}
routePlanningRepository.startRoutePlanning(queue);
@@ -135,11 +132,7 @@ class NetMessageDispatcher {
/// [commandCode] 指令码
/// [statusIndex] 状态字节在 payload 中的索引
/// [expectedStatus] 期望的状态值
Stream<RawPacket> onStatusResponse({
required int commandCode,
required int statusIndex,
required int expectedStatus,
}) {
Stream<RawPacket> onStatusResponse({required int commandCode, required int statusIndex, required int expectedStatus}) {
debugPrint('🔍 [Dispatcher] 监听指令应答 CMD: 0x${commandCode.toRadixString(16)}, 期望状态:0x${expectedStatus.toRadixString(16)}');
return onCommand(commandCode).where((packet) {

View File

@@ -85,6 +85,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
bool _isRefreshing = false; // 新增:页面刷新状态标志
bool _isVideoDialogOpen = false; // 控制视频弹窗显示
String _videoStreamUrl = "";
bool isStopWork = false; //是否点击过停止
Offset _videoPopupPos = const Offset(0, 100); // 弹窗初始位置
// 🔥 关键修复:添加截图全局Key
final GlobalKey _mapRepaintKey = GlobalKey();
@@ -381,23 +382,23 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
return;
}
if (isStartWork && headingStatus == 0) {
if (isStartWork && headingStatus == 0 && !isStopWork) {
if (!_showHeadingWarn) {
// 仅状态变化时更新,避免重复刷新
setState(() => _showHeadingWarn = true);
}
return;
} else if (isStartWork && headingStatus == 1 && _showHeadingWarn) {
} else if (isStartWork && headingStatus == 1 && _showHeadingWarn && !isStopWork) {
// 条件不满足时隐藏提示
setState(() => _showHeadingWarn = false);
}
if (isStartWork && controlMode != "3") {
if (isStartWork && controlMode != "3" && !isStopWork) {
if (!_showControlModeWarn) {
// 仅状态变化时更新
setState(() => _showControlModeWarn = true);
}
} else if (isStartWork && controlMode == "3" && _showControlModeWarn) {
} else if (isStartWork && controlMode == "3" && _showControlModeWarn && !isStopWork) {
// 条件不满足时隐藏提示
setState(() => _showControlModeWarn = false);
}
@@ -815,6 +816,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
isDjMapShow = false;
_workStatus = WorkStatus.idle;
isStartWork = false;
isStopWork = false;
});
_clearLocalData();
@@ -1461,8 +1463,8 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
for (int i = 0; i < gctracePoint!.length - 1; i++)
Polyline(
points: [gctracePoint![i], gctracePoint![i + 1]],
color: Colors.white,
strokeWidth: 1.5,
color: Colors.blueAccent,
strokeWidth: 3,
isDotted: true, // 虚线区分作业区域
),
],
@@ -1473,11 +1475,11 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
/// 开始作业
void _startWork() async {
isStopWork = false;
if (startWorkList.isEmpty) {
ToastUtils.showInfo(context, '作业列表为空,请重新选择路径');
return;
}
isStartWork = true;
_traceManager.setMode(TPMode.NAVIGATION);
setState(() {
@@ -1490,7 +1492,6 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
// 🔥 延迟一下,确保状态已更新
await Future.delayed(const Duration(milliseconds: 100));
//// 步骤1:将 List<LatLng> 转换为 List<DeviceAddPathPointModel>
//final List<work_area_model.DeviceAddPathPointModel> pathModels = gcjPathPoints.map((latLng) {
// return work_area_model.DeviceAddPathPointModel(
@@ -1508,6 +1509,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
// 步骤 3:调用 Cubit 方法(类型匹配)
await context.read<DevicesCubit>().startRoutePlanning(pathQueue);
///context.read<DevicesCubit>().updateAppState(AppState.routePlanning);
// 可选:显示作业提示
ToastUtils.showSuccess(context, '作业已开始');
@@ -1530,6 +1532,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
_workStatus = WorkStatus.idle;
_showHeadingWarn = false;
_showControlModeWarn = false;
isStopWork = true; //已经点击过停止
});
_traceManager.setMode(TPMode.LOCATION);
context.read<DevicesCubit>().updateAppState(AppState.none);
@@ -1630,6 +1633,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
_showControlModeWarn = false;
isStartWork = false;
});
if (isStopWork) return;
_stopWork();
},
icon: const Icon(Icons.close, color: Colors.grey, size: 20),
@@ -1642,30 +1646,30 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
const SizedBox(height: 16),
// 2. 错误提示(如果加载失败)
if (state.errorMessage != null)
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: Colors.red[50],
borderRadius: BorderRadius.circular(6),
border: Border.all(color: Colors.red[200]!),
),
child: Row(
children: [
const Icon(Icons.error_outline, color: Colors.redAccent, size: 16),
const SizedBox(width: 8),
Expanded(
child: Text(
state.errorMessage!,
style: const TextStyle(fontSize: 14, color: Colors.redAccent),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
//if (state.errorMessage != null)
// Container(
// padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
// margin: const EdgeInsets.only(bottom: 12),
// decoration: BoxDecoration(
// color: Colors.red[50],
// borderRadius: BorderRadius.circular(6),
// border: Border.all(color: Colors.red[200]!),
// ),
// child: Row(
// children: [
// const Icon(Icons.error_outline, color: Colors.redAccent, size: 16),
// const SizedBox(width: 8),
// Expanded(
// child: Text(
// state.errorMessage!,
// style: const TextStyle(fontSize: 14, color: Colors.redAccent),
// maxLines: 2,
// overflow: TextOverflow.ellipsis,
// ),
// ),
// ],
// ),
// ),
// 3. 开始作业按钮(加载中禁用)
// 放在 Column/Row 的 children: [ ... ] 内部
@@ -2034,6 +2038,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
LatLng? targetLatLng;
if (arriLatitude != null && arriLongitude != null) {
targetLatLng = LatLng(arriLatitude, arriLongitude);
debugPrint("${targetLatLng}收到完成点gctracePoint");
_traceManager.upsert(targetLatLng, TPAction.ADD);
}
@@ -2043,11 +2048,12 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
int headingStatus = 0;
String controlMode = "0";
DeviceStatusUpdated? updatedState;
//有停止信号
if (isFinishWork) {
_workStatus = WorkStatus.idle;
ToastUtils.showError(context, '作业已停止');
isStartWork = false;
_traceManager.setMode(TPMode.LOCATION);
isStopWork = true;
}
if (state is DeviceStatusUpdated) {

View File

@@ -71,9 +71,9 @@ class MyPage extends StatelessWidget {
// 添加 context 参数
return BannerCarousel(
items: [
BannerItem(image: 'https://c.53326.com/d/file/lan20221010/fyhj0ibovbp.jpg', title: 'AI赋能农业', url: 'https://www.satabot.com/'),
BannerItem(image: 'https://picsum.photos/800/400?1', title: '智能农机上新', url: 'https://www.satabot.com/'),
BannerItem(image: 'https://picsum.photos/800/400?2', title: '科技改变生活', url: 'https://www.satabot.com/'),
BannerItem(image: 'assets/images/carousel3.jpg', title: 'AI赋能农业', url: 'https://www.satabot.com/'),
BannerItem(image: 'assets/images/carousel1.png', title: '智能农机上新', url: 'https://www.satabot.com/'),
BannerItem(image: 'assets/images/carousel2.png', title: '科技改变生活', url: 'https://www.satabot.com/'),
],
);
}