主界面 作业里成接入
This commit is contained in:
@@ -777,15 +777,24 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
|
||||
}
|
||||
|
||||
Widget _buildTab(String title, {required bool isActive}) {
|
||||
return Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: isActive ? const Color(0xFF1677FF) : const Color(0xFF666666),
|
||||
fontSize: 16,
|
||||
fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
|
||||
decoration: isActive ? TextDecoration.underline : null,
|
||||
decorationColor: const Color(0xFF1677FF),
|
||||
decorationThickness: 2,
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 4), // 控制整体间距
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: isActive ? const Color(0xFF1677FF) : Colors.transparent,
|
||||
width: 2, // 下划线粗细
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: isActive ? const Color(0xFF1677FF) : const Color(0xFF666666),
|
||||
fontSize: 16,
|
||||
fontWeight: isActive ? FontWeight.w600 : FontWeight.normal,
|
||||
height: 1.0, // 文字行高
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -881,7 +890,7 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
|
||||
child: Container(
|
||||
color: Colors.white,
|
||||
margin: const EdgeInsets.only(top: 8),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@@ -902,11 +911,15 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF1677FF),
|
||||
foregroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
elevation: 2,
|
||||
shadowColor: const Color(0xFF1677FF).withOpacity(0.3),
|
||||
shape: const CircleBorder(),
|
||||
// 👇 圆形必须用对称内边距
|
||||
padding: const EdgeInsets.all(12),
|
||||
//padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
|
||||
),
|
||||
onPressed: _refreshDeviceData,
|
||||
child: const Text("刷新数据", style: TextStyle(fontSize: 14)),
|
||||
child: const Icon(Icons.refresh_rounded, size: 18),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -937,10 +937,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
if (_workStatus != WorkStatus.idle) {
|
||||
_stopWork();
|
||||
}
|
||||
//if (_workStatus != WorkStatus.idle) {
|
||||
// _showPageToast(message: "请先停止作业再刷新页面哦!", type: ToastType.warn);
|
||||
// return;
|
||||
//}
|
||||
|
||||
_cancelAllToast();
|
||||
if (_isRefreshing) return;
|
||||
|
||||
@@ -952,8 +949,9 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
if (_currentLatLng != null && _isValidLatLng(_currentLatLng!.latitude, _currentLatLng!.longitude)) {
|
||||
_mapController.move(_currentLatLng!, 18);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 🔥 1. 清空 所有本地缓存(你要的核心功能)
|
||||
// 🔥 1. 清空 所有本地缓存
|
||||
// ==========================================
|
||||
await _clearLocalData();
|
||||
|
||||
@@ -961,7 +959,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
// 🔥 2. 清空 所有内存状态(彻底重置)
|
||||
// ==========================================
|
||||
setState(() {
|
||||
// 轨迹彻底清空
|
||||
// 轨迹彻底清空(关键!)
|
||||
tracePoint?.clear();
|
||||
gctracePoint?.clear();
|
||||
tracePoint = [];
|
||||
@@ -1001,15 +999,15 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
isStartWork = false;
|
||||
isStopWork = false;
|
||||
isreceiveFirstCompletePoint = false;
|
||||
_showHeadingWarn = false; // 关闭航向警告
|
||||
_isPanelOpen = false; // 关闭底部操作面板
|
||||
_showHeadingWarn = false;
|
||||
_isPanelOpen = false;
|
||||
|
||||
_directionBoxOpen = false; // 关闭航线方向面板
|
||||
_isListBoxOpen = false; // 关闭地块列表面板
|
||||
_isWorkPanelOpen = false; // 关闭作业面板
|
||||
_isVideoDialogOpen = false; // 关闭视频弹窗
|
||||
_isObstacleEditing = false; // 退出障碍物编辑
|
||||
_selectedPlot = null; // 清空选中地块
|
||||
_directionBoxOpen = false;
|
||||
_isListBoxOpen = false;
|
||||
_isWorkPanelOpen = false;
|
||||
_isVideoDialogOpen = false;
|
||||
_isObstacleEditing = false;
|
||||
_selectedPlot = null;
|
||||
|
||||
// 重置模式
|
||||
_currentRobotMode = RobotMode.robot;
|
||||
@@ -1020,35 +1018,28 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
_workDistance = 0.0;
|
||||
_angle = 0.0;
|
||||
|
||||
// 选中地块清空
|
||||
_selectedPlot = null;
|
||||
|
||||
// 定位重置
|
||||
_currentLatLng = null;
|
||||
_currentWgsLatLng = null;
|
||||
_currentLatLng = null;
|
||||
_currentWgsLatLng = null;
|
||||
_mapCenter = _getDefaultValidCenter();
|
||||
|
||||
// 重置作业状态
|
||||
isDjMapShow = false;
|
||||
_workStatus = WorkStatus.idle;
|
||||
isStartWork = false;
|
||||
isStopWork = false;
|
||||
|
||||
// 轨迹管理器重置
|
||||
// ==========================================
|
||||
// 🔥 🔥 🔥 核心修复:强制重置轨迹管理器 + 强制改为 LOCATION 模式
|
||||
// ==========================================
|
||||
_traceManager.reset();
|
||||
_traceManager.setMode(TPMode.LOCATION);
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 🔥 3. 保存空状态(确保下次打开也是干净的)
|
||||
// 🔥 3. 保存空状态
|
||||
// ==========================================
|
||||
await _saveDataToLocal();
|
||||
|
||||
// 移动地图到默认中心点
|
||||
//_mapController.move(_getDefaultValidCenter(), 18);
|
||||
|
||||
if (mounted) {
|
||||
_showPageToast(message: "已清除所有缓存,恢复初始状态", type: ToastType.success);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.
|
||||
import 'package:maibu_satabot_v2/features/devices/domain/usecases/device_work_hostrirty_usecase.dart';
|
||||
import 'package:maibu_satabot_v2/features/devices/domain/entities/device_run_hostrity_entity.dart';
|
||||
import 'package:maibu_satabot_v2/features/devices/domain/errors/device_failure.dart';
|
||||
|
||||
import 'package:maibu_satabot_v2/features/devices/presentation/bloc/device_status_bloc.dart';
|
||||
import 'package:maibu_satabot_v2/features/devices/presentation/bloc/device_status_state.dart';
|
||||
import '../../../../core/di/injection.dart';
|
||||
import '../../../devices/presentation/bloc/devices_cubit.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class WorkParamsCard extends StatefulWidget {
|
||||
const WorkParamsCard({super.key});
|
||||
@@ -19,25 +21,36 @@ class WorkParamsCard extends StatefulWidget {
|
||||
class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
List<DeviceRunStatisticsEntity>? _statistics;
|
||||
String? _errorMessage;
|
||||
bool _isLoading = false; // 默认不加载
|
||||
bool _isLoading = false;
|
||||
|
||||
// 计时相关
|
||||
DateTime? _firstTimestamp; // 第一次时间(开始时间)
|
||||
int _totalWorkMinutes = 0; // 总作业分钟
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final deviceState = context.watch<DevicesCubit>().state;
|
||||
final currentDevice = deviceState.selectedDevice;
|
||||
final statusState = context.watch<DeviceStatusBloc>().state;
|
||||
|
||||
double? distance;
|
||||
double? workArea;
|
||||
|
||||
if (statusState is DeviceStatusUpdated) {
|
||||
workArea = double.tryParse(statusState.status.workingArea ?? '');
|
||||
distance = workArea != null ? workArea / 0.7 : null;
|
||||
|
||||
// ====================== 计算作业时长(核心) ======================
|
||||
_calculateWorkingTime(statusState.status.timestamp);
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.02),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 10, offset: const Offset(0, 4))],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -50,34 +63,26 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
Container(
|
||||
width: 4,
|
||||
height: 16,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blueAccent,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
decoration: BoxDecoration(color: Colors.blueAccent, borderRadius: BorderRadius.circular(2)),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'作业参数',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black),
|
||||
),
|
||||
],
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
_handleInfoTap(currentDevice); // 包装在同步函数中
|
||||
}, // 点击事件处理
|
||||
if (currentDevice != null) {
|
||||
_handleInfoTap(currentDevice);
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.info, size: 14, color: Colors.grey[400]),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'查看详情',
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey[400]),
|
||||
),
|
||||
Text('查看详情', style: TextStyle(fontSize: 12, color: Colors.grey[400])),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -87,11 +92,12 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
IntrinsicHeight(
|
||||
child: Row(
|
||||
children: [
|
||||
_buildParamItem('作业面积', '0', '亩'), // 默认值
|
||||
_buildParamItem('作业面积', '${workArea?.toStringAsFixed(1) ?? '0'}', '㎡'),
|
||||
_buildDivider(),
|
||||
_buildParamItem('作业里程', '0', 'km'),
|
||||
_buildParamItem('作业里程', '${distance?.toStringAsFixed(1) ?? '0'}', 'm'),
|
||||
_buildDivider(),
|
||||
_buildParamItem('作业时长', '0', 'h'),
|
||||
// 显示实时计算的作业时长
|
||||
_buildParamItem('作业时长', '${_totalWorkMinutes}', 'min'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -100,22 +106,39 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
);
|
||||
}
|
||||
|
||||
// 点击事件处理
|
||||
Future<void> _handleInfoTap(DeviceEntity? currentDevice) async {
|
||||
print("点击触摸了历史作业");
|
||||
// ====================== 核心:根据时间戳计算时长 ======================
|
||||
void _calculateWorkingTime(String timestampStr) {
|
||||
try {
|
||||
// 你的时间格式:20-1-11-31 08:00:00
|
||||
DateTime currentTime = DateFormat("yy-MM-dd HH:mm:ss").parse(timestampStr);
|
||||
|
||||
// 第一次进入,记录开始时间
|
||||
if (_firstTimestamp == null) {
|
||||
setState(() {
|
||||
_firstTimestamp = currentTime;
|
||||
});
|
||||
}
|
||||
|
||||
// 计算相差分钟数
|
||||
final diff = currentTime.difference(_firstTimestamp!);
|
||||
setState(() {
|
||||
_totalWorkMinutes = diff.inMinutes;
|
||||
});
|
||||
} catch (e) {
|
||||
debugPrint("时间解析失败: $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleInfoTap(DeviceEntity currentDevice) async {
|
||||
setState(() {
|
||||
_isLoading = true; // 开始加载
|
||||
_errorMessage = null; // 清除错误信息
|
||||
_isLoading = true;
|
||||
_errorMessage = null;
|
||||
});
|
||||
print("开始历史作业");
|
||||
try {
|
||||
final useCase = DeviceWorkHostrirty(sl());
|
||||
print("发送获取历史作业记录开始");
|
||||
//displayName
|
||||
final deviceId = currentDevice?.deviceName.toString() ?? '';
|
||||
final deviceId = currentDevice.deviceName.toString() ?? '';
|
||||
final params = BindDeviceParams(deviceId, 'your_device_alias');
|
||||
final result = await useCase(params);
|
||||
print("发送获取历史作业记录结束");
|
||||
result.fold(
|
||||
(failure) {
|
||||
setState(() {
|
||||
@@ -128,11 +151,10 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
_statistics = data;
|
||||
_isLoading = false;
|
||||
});
|
||||
_showDetailsDialog(context, _statistics!); // 展示弹窗
|
||||
_showDetailsDialog(context, _statistics!);
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
print("捕获异常: $e");
|
||||
setState(() {
|
||||
_errorMessage = '请求失败: $e';
|
||||
_isLoading = false;
|
||||
@@ -140,23 +162,15 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
}
|
||||
}
|
||||
|
||||
// 弹窗展示详情
|
||||
// 弹窗展示详情(从底部弹出)
|
||||
// 弹窗展示详情(从底部弹出,覆盖底部导航栏)
|
||||
void _showDetailsDialog(
|
||||
BuildContext context,
|
||||
List<DeviceRunStatisticsEntity> data,
|
||||
) {
|
||||
void _showDetailsDialog(BuildContext context, List<DeviceRunStatisticsEntity> data) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true, // 支持全屏高度
|
||||
useRootNavigator: true, // 覆盖底部导航栏
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)), // 顶部圆角
|
||||
),
|
||||
isScrollControlled: true,
|
||||
useRootNavigator: true,
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(20))),
|
||||
builder: (context) {
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height * 0.75, // 占据屏幕 75% 高度
|
||||
height: MediaQuery.of(context).size.height * 0.75,
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
@@ -165,21 +179,14 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 顶部区域:拖拽指示器 + 标题 + 关闭按钮
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// 顶部拖拽指示器(居中改左对齐,和关闭按钮形成布局)
|
||||
Center(child: Container(width: 40, height: 4)),
|
||||
const Text(
|
||||
'历史记录详情',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black87),
|
||||
),
|
||||
// 右上角关闭按钮(X号)
|
||||
IconButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: const Icon(Icons.close, color: Colors.grey, size: 24),
|
||||
@@ -189,73 +196,38 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
// 内容区域(增加无数据判断)
|
||||
Expanded(
|
||||
child: data.isEmpty
|
||||
? // 无数据时显示占位
|
||||
const Center(
|
||||
? const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.description_outlined,
|
||||
size: 60,
|
||||
color: Colors.grey,
|
||||
),
|
||||
Icon(Icons.description_outlined, size: 60, color: Colors.grey),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
'暂无历史记录',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
Text('暂无历史记录', style: TextStyle(fontSize: 16, color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
)
|
||||
: // 有数据时显示列表
|
||||
SingleChildScrollView(
|
||||
: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: data.map((item) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.withOpacity(0.05), // 浅蓝背景
|
||||
color: Colors.blue.withOpacity(0.05),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: Colors.blue.withOpacity(0.2),
|
||||
width: 1,
|
||||
),
|
||||
border: Border.all(color: Colors.blue.withOpacity(0.2), width: 1),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildDetailRow(
|
||||
Icons.calendar_today,
|
||||
'开始时间',
|
||||
item.startTime,
|
||||
),
|
||||
_buildDetailRow(
|
||||
Icons.calendar_today_outlined,
|
||||
'结束时间',
|
||||
item.endTime,
|
||||
),
|
||||
_buildDetailRow(
|
||||
Icons.square_foot,
|
||||
'工作面积',
|
||||
'${item.workArea} 亩',
|
||||
),
|
||||
_buildDetailRow(
|
||||
Icons.directions_car,
|
||||
'工作距离',
|
||||
'${item.distance?.toStringAsFixed(2) ?? '未计算'} km',
|
||||
),
|
||||
_buildDetailRow(
|
||||
Icons.timer,
|
||||
'花费时间',
|
||||
'${item.time} 小时',
|
||||
),
|
||||
_buildDetailRow(Icons.calendar_today, '开始时间', item.startTime),
|
||||
_buildDetailRow(Icons.calendar_today_outlined, '结束时间', item.endTime),
|
||||
_buildDetailRow(Icons.square_foot, '工作面积', '${item.workArea} ㎡'),
|
||||
if (item.distance != null && item.distance! > 0)
|
||||
_buildDetailRow(Icons.directions_car, '工作距离', '${item.distance!.toStringAsFixed(2)} m'),
|
||||
_buildDetailRow(Icons.timer, '花费时间', '${item.time} min'),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -263,7 +235,6 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
),
|
||||
),
|
||||
),
|
||||
// 移除原有底部关闭按钮
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -271,7 +242,6 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
);
|
||||
}
|
||||
|
||||
// 构建详情行
|
||||
Widget _buildDetailRow(IconData icon, String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
@@ -281,24 +251,16 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'$label: ',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black87,
|
||||
),
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.black87),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
style: const TextStyle(fontSize: 14, color: Colors.black54),
|
||||
),
|
||||
child: Text(value, style: const TextStyle(fontSize: 14, color: Colors.black54)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 构建单个参数项
|
||||
Widget _buildParamItem(String label, String value, String unit) {
|
||||
return Expanded(
|
||||
child: Column(
|
||||
@@ -316,10 +278,7 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
color: Colors.black38,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(fontSize: 12, color: Colors.black38),
|
||||
),
|
||||
Text(label, style: const TextStyle(fontSize: 12, color: Colors.black38)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -328,20 +287,11 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
children: [
|
||||
TextSpan(
|
||||
text: value,
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.black,
|
||||
fontFamily: 'Inter',
|
||||
),
|
||||
style: const TextStyle(fontSize: 28, fontWeight: FontWeight.w700, color: Colors.black, fontFamily: 'Inter'),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' $unit',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Colors.black54,
|
||||
),
|
||||
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.normal, color: Colors.black54),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -351,13 +301,7 @@ class _WorkParamsCardState extends State<WorkParamsCard> {
|
||||
);
|
||||
}
|
||||
|
||||
// 垂直分割线
|
||||
Widget _buildDivider() {
|
||||
return VerticalDivider(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
thickness: 1,
|
||||
indent: 10,
|
||||
endIndent: 10,
|
||||
);
|
||||
return VerticalDivider(color: Colors.black.withOpacity(0.05), thickness: 1, indent: 10, endIndent: 10);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,7 @@ class LeftJoystickArea extends StatelessWidget {
|
||||
final bool isLocked;
|
||||
final double width;
|
||||
|
||||
const LeftJoystickArea({
|
||||
Key? key,
|
||||
required this.isLocked,
|
||||
required this.width,
|
||||
}) : super(key: key);
|
||||
const LeftJoystickArea({Key? key, required this.isLocked, required this.width}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -31,6 +27,7 @@ class LeftJoystickArea extends StatelessWidget {
|
||||
radius: width, // 对应 size(200.dp)
|
||||
axisHint: AxisHint.forwardBackward,
|
||||
onValueChanged: (value) {
|
||||
debugPrint('🎮 [左摇杆] value: ${value.y},${value.x}');
|
||||
// 对应 viewModel.updateOriginY(y)
|
||||
context.read<RemoteControlCubit>().updateOriginY(value.y);
|
||||
Future.delayed(const Duration(milliseconds: 50), () {
|
||||
@@ -48,26 +45,25 @@ class LeftJoystickArea extends StatelessWidget {
|
||||
const SizedBox(height: 18),
|
||||
Text(
|
||||
"前后控制",
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: 0.5),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: 0.5), fontSize: 12, fontWeight: FontWeight.w500),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _triggerVibration() {
|
||||
Vibration.hasVibrator().then((hasVibrator) {
|
||||
if (hasVibrator ?? false) {
|
||||
Vibration.vibrate(duration: 12);
|
||||
debugPrint('📳 [右摇杆] 震动执行 - 10ms');
|
||||
} else {
|
||||
debugPrint('⚠️ [右摇杆] 设备不支持震动');
|
||||
}
|
||||
}).catchError((e) {
|
||||
debugPrint('❌ [右摇杆] 震动失败:$e');
|
||||
});
|
||||
Vibration.hasVibrator()
|
||||
.then((hasVibrator) {
|
||||
if (hasVibrator ?? false) {
|
||||
Vibration.vibrate(duration: 12);
|
||||
debugPrint('📳 [右摇杆] 震动执行 - 10ms');
|
||||
} else {
|
||||
debugPrint('⚠️ [右摇杆] 设备不支持震动');
|
||||
}
|
||||
})
|
||||
.catchError((e) {
|
||||
debugPrint('❌ [右摇杆] 震动失败:$e');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user