356 lines
12 KiB
Dart
356 lines
12 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:fpdart/fpdart.dart' hide State;
|
|
import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.dart';
|
|
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 '../../../../core/di/injection.dart';
|
|
import '../../../devices/presentation/bloc/devices_cubit.dart';
|
|
|
|
class WorkParamsCard extends StatefulWidget {
|
|
const WorkParamsCard({super.key});
|
|
|
|
@override
|
|
State<WorkParamsCard> createState() => _WorkParamsCardState();
|
|
}
|
|
|
|
class _WorkParamsCardState extends State<WorkParamsCard> {
|
|
List<DeviceRunStatisticsEntity>? _statistics;
|
|
String? _errorMessage;
|
|
bool _isLoading = false; // 默认不加载
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final deviceState = context.watch<DevicesCubit>().state;
|
|
final currentDevice = deviceState.selectedDevice;
|
|
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),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Container(
|
|
width: 4,
|
|
height: 16,
|
|
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,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
GestureDetector(
|
|
onTap: () {
|
|
_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]),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 24),
|
|
IntrinsicHeight(
|
|
child: Row(
|
|
children: [
|
|
_buildParamItem('作业面积', '0', '亩'), // 默认值
|
|
_buildDivider(),
|
|
_buildParamItem('作业里程', '0', 'km'),
|
|
_buildDivider(),
|
|
_buildParamItem('作业时长', '0', 'h'),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// 点击事件处理
|
|
Future<void> _handleInfoTap(DeviceEntity? currentDevice) async {
|
|
print("点击触摸了历史作业");
|
|
setState(() {
|
|
_isLoading = true; // 开始加载
|
|
_errorMessage = null; // 清除错误信息
|
|
});
|
|
print("开始历史作业");
|
|
try {
|
|
final useCase = DeviceWorkHostrirty(sl());
|
|
print("发送获取历史作业记录开始");
|
|
//displayName
|
|
final deviceId = currentDevice?.deviceName.toString() ?? '';
|
|
final params = BindDeviceParams(deviceId, 'your_device_alias');
|
|
final result = await useCase(params);
|
|
print("发送获取历史作业记录结束");
|
|
result.fold(
|
|
(failure) {
|
|
setState(() {
|
|
_errorMessage = failure.message;
|
|
_isLoading = false;
|
|
});
|
|
},
|
|
(data) {
|
|
setState(() {
|
|
_statistics = data;
|
|
_isLoading = false;
|
|
});
|
|
_showDetailsDialog(context, _statistics!); // 展示弹窗
|
|
},
|
|
);
|
|
} catch (e) {
|
|
print("捕获异常: $e");
|
|
setState(() {
|
|
_errorMessage = '请求失败: $e';
|
|
_isLoading = false;
|
|
});
|
|
}
|
|
}
|
|
|
|
// 弹窗展示详情
|
|
// 弹窗展示详情(从底部弹出)
|
|
// 弹窗展示详情(从底部弹出,覆盖底部导航栏)
|
|
void _showDetailsDialog(
|
|
BuildContext context,
|
|
List<DeviceRunStatisticsEntity> data,
|
|
) {
|
|
showModalBottomSheet(
|
|
context: context,
|
|
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% 高度
|
|
padding: const EdgeInsets.all(20),
|
|
decoration: const BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// 顶部拖拽指示器
|
|
Center(
|
|
child: Container(
|
|
width: 40,
|
|
height: 4,
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[300],
|
|
borderRadius: BorderRadius.circular(2),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
// 标题
|
|
const Text(
|
|
'历史记录详情',
|
|
style: TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.black87,
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
// 内容区域
|
|
Expanded(
|
|
child: 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), // 浅蓝背景
|
|
borderRadius: BorderRadius.circular(12),
|
|
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} 小时',
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
// 关闭按钮
|
|
Align(
|
|
alignment: Alignment.centerRight,
|
|
child: ElevatedButton(
|
|
onPressed: () => Navigator.pop(context),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.blue,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
),
|
|
child: const Text(
|
|
'关闭',
|
|
style: TextStyle(color: Colors.white),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
// 构建详情行
|
|
Widget _buildDetailRow(IconData icon, String label, String value) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
|
child: Row(
|
|
children: [
|
|
Icon(icon, size: 16, color: Colors.blue),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'$label: ',
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.black87,
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Text(
|
|
value,
|
|
style: const TextStyle(fontSize: 14, color: Colors.black54),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// 构建单个参数项
|
|
Widget _buildParamItem(String label, String value, String unit) {
|
|
return Expanded(
|
|
child: Column(
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
label == '作业面积'
|
|
? Icons.aspect_ratio
|
|
: label == '作业里程'
|
|
? Icons.local_shipping_outlined
|
|
: Icons.access_time,
|
|
size: 14,
|
|
color: Colors.black38,
|
|
),
|
|
const SizedBox(width: 4),
|
|
Text(
|
|
label,
|
|
style: const TextStyle(fontSize: 12, color: Colors.black38),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
RichText(
|
|
text: TextSpan(
|
|
children: [
|
|
TextSpan(
|
|
text: value,
|
|
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,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// 垂直分割线
|
|
Widget _buildDivider() {
|
|
return VerticalDivider(
|
|
color: Colors.black.withOpacity(0.05),
|
|
thickness: 1,
|
|
indent: 10,
|
|
endIndent: 10,
|
|
);
|
|
}
|
|
}
|