437 lines
15 KiB
Dart
437 lines
15 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:getx_scaffold/getx_scaffold.dart';
|
|
import 'package:ln_jq_app/common/styles/theme.dart';
|
|
|
|
import 'controller.dart';
|
|
|
|
///加氢预约
|
|
class SitePage extends GetView<SiteController> {
|
|
const SitePage({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GetBuilder<SiteController>(
|
|
init: SiteController(),
|
|
id: 'site',
|
|
builder: (_) {
|
|
return SingleChildScrollView(child: _buildView());
|
|
},
|
|
);
|
|
}
|
|
|
|
// 主视图
|
|
Widget _buildView() {
|
|
return Padding(
|
|
padding: const EdgeInsets.all(12.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
// 第一个卡片: 今日预约统计
|
|
Card(
|
|
elevation: 3,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
|
|
margin: const EdgeInsets.only(bottom: 12),
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 12.0),
|
|
child: Column(
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.calendar_today, color: Colors.blue, size: 32),
|
|
const SizedBox(width: 12),
|
|
const Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'今日预约统计',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
Text(
|
|
"Today's Reservation Statistics",
|
|
style: TextStyle(fontSize: 12, color: Colors.grey),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: 10,
|
|
vertical: 4,
|
|
),
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.withOpacity(0.1),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: const Text(
|
|
'实时',
|
|
style: TextStyle(
|
|
color: Colors.blue,
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
const Divider(height: 1, indent: 16, endIndent: 16),
|
|
const SizedBox(height: 12),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: [
|
|
_buildStatItem(controller.leftHydrogen, '剩余余量'),
|
|
_buildStatItem(controller.orderAmount, '预约车辆'),
|
|
_buildStatItem(controller.completedAmount, '已完成'),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
|
|
// 第二个卡片: 预约信息
|
|
Card(
|
|
elevation: 3,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
|
|
margin: const EdgeInsets.only(bottom: 12),
|
|
clipBehavior: Clip.antiAlias,
|
|
child: Column(
|
|
children: [
|
|
Container(
|
|
color: Colors.blue,
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
|
|
child: Row(
|
|
children: [
|
|
const Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'今日预约信息',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
SizedBox(height: 2),
|
|
Text(
|
|
'Reservation Information',
|
|
style: TextStyle(fontSize: 12, color: Colors.white70),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
ElevatedButton.icon(
|
|
onPressed: () {
|
|
controller.fetchReservationData();
|
|
},
|
|
icon: const Icon(Icons.refresh, size: 16),
|
|
label: const Text('刷新'),
|
|
style: ElevatedButton.styleFrom(
|
|
foregroundColor: Colors.blue,
|
|
backgroundColor: Colors.white,
|
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
controller.hasReservationData
|
|
? _buildReservationListView()
|
|
: _buildEmptyReservationView(),
|
|
],
|
|
),
|
|
),
|
|
|
|
//第三部分
|
|
Card(
|
|
elevation: 3,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
|
|
margin: const EdgeInsets.only(bottom: 12),
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
_buildInfoItem(Icons.info_outline, '数据每5分钟自动刷新一次'),
|
|
const SizedBox(height: 8),
|
|
_buildInfoItem(Icons.headset_mic_outlined, '如有疑问请联系客服: 400-021-1773'),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 构建单个统计项
|
|
Widget _buildStatItem(String value, String label, {Color valueColor = Colors.blue}) {
|
|
return Expanded(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
value,
|
|
style: TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold,
|
|
color: valueColor,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(label, style: const TextStyle(fontSize: 14, color: Colors.grey)),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 构建“暂无预约数据”的视图
|
|
Widget _buildEmptyReservationView() {
|
|
return Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.symmetric(vertical: 48.0),
|
|
color: Colors.white,
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(Icons.inventory_2_outlined, size: 80, color: Colors.grey[300]),
|
|
const SizedBox(height: 16),
|
|
const Text('暂无预约数据', style: TextStyle(fontSize: 16, color: Colors.black54)),
|
|
const SizedBox(height: 8),
|
|
const Text(
|
|
'点击右上角刷新按钮获取最新数据',
|
|
style: TextStyle(fontSize: 14, color: Colors.grey),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 构建“有预约数据”的列表视图
|
|
Widget _buildReservationListView() {
|
|
return Container(
|
|
color: Colors.white,
|
|
child: ListView.separated(
|
|
shrinkWrap: true,
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
// 因为外层已有滚动,这里禁用内部滚动
|
|
itemCount: controller.reservationList.length,
|
|
padding: const EdgeInsets.all(12.0),
|
|
itemBuilder: (context, index) {
|
|
final item = controller.reservationList[index];
|
|
// 调用新的方法来构建每一项
|
|
return _buildReservationItem(index, item);
|
|
},
|
|
separatorBuilder: (context, index) => const SizedBox(height: 12), // 列表项之间的间距
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildReservationItem(int index, ReservationModel item) {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(8.0),
|
|
border: Border.all(color: Colors.grey[200]!, width: 1.0),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.grey.withOpacity(0.1),
|
|
spreadRadius: 1,
|
|
blurRadius: 3,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
children: [
|
|
// 顶部:序号、车牌号、状态
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(8, 12, 16, 12),
|
|
child: Row(
|
|
children: [
|
|
// 序号
|
|
Container(
|
|
width: 24,
|
|
height: 24,
|
|
alignment: Alignment.center,
|
|
decoration: const BoxDecoration(
|
|
color: Colors.blue,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Text(
|
|
"${index + 1}",
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 8),
|
|
const Icon(Icons.directions_car, color: Colors.black54),
|
|
const SizedBox(width: 4),
|
|
// 车牌号
|
|
Expanded(
|
|
child: Text(
|
|
item.plateNumber,
|
|
style: const TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: AppTheme.themeColor,
|
|
),
|
|
),
|
|
),
|
|
// 状态标签
|
|
_buildStatusChip(item.status),
|
|
],
|
|
),
|
|
),
|
|
const Divider(height: 1),
|
|
// 中部:详细信息
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
|
|
child: Column(
|
|
children: [
|
|
_buildDetailRow(
|
|
Icons.local_gas_station,
|
|
'加氢量',
|
|
item.amount,
|
|
valueColor: Colors.red,
|
|
),
|
|
const SizedBox(height: 8),
|
|
_buildDetailRow(Icons.access_time, '预约时间', item.time),
|
|
const SizedBox(height: 8),
|
|
_buildDetailRow(Icons.person, '联系人', item.contactPerson),
|
|
const SizedBox(height: 8),
|
|
_buildDetailRow(
|
|
Icons.phone,
|
|
'联系电话',
|
|
item.contactPhone,
|
|
valueColor: AppTheme.themeColor,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
// 底部:操作按钮 (仅在待处理时显示)
|
|
if (item.status == ReservationStatus.pending)
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(16, 0, 16, 12),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: ElevatedButton(
|
|
onPressed: () => controller.confirmReservation(item.id),
|
|
style: ElevatedButton.styleFrom(backgroundColor: Colors.blue),
|
|
child: const Text('确定'),
|
|
),
|
|
),
|
|
const SizedBox(width: 16),
|
|
Expanded(
|
|
child: ElevatedButton(
|
|
onPressed: () => controller.rejectReservation(item.id),
|
|
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
|
child: const Text('拒绝'),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 构建状态标签
|
|
Widget _buildStatusChip(ReservationStatus status) {
|
|
String text;
|
|
Color color;
|
|
switch (status) {
|
|
case ReservationStatus.pending:
|
|
text = '待处理';
|
|
color = Colors.orange;
|
|
break;
|
|
case ReservationStatus.completed:
|
|
text = '已完成';
|
|
color = Colors.greenAccent;
|
|
break;
|
|
case ReservationStatus.rejected:
|
|
text = '已拒绝';
|
|
color = Colors.red;
|
|
break;
|
|
default:
|
|
text = '未知状态';
|
|
color = Colors.grey;
|
|
break;
|
|
}
|
|
return Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
decoration: BoxDecoration(
|
|
color: color.withOpacity(0.1),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(Icons.circle, color: color, size: 8),
|
|
const SizedBox(width: 4),
|
|
Text(
|
|
text,
|
|
style: TextStyle(color: color, fontSize: 12, fontWeight: FontWeight.bold),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 构建信息详情行
|
|
Widget _buildDetailRow(
|
|
IconData icon,
|
|
String label,
|
|
String value, {
|
|
Color valueColor = Colors.black87,
|
|
}) {
|
|
return Row(
|
|
children: [
|
|
Icon(icon, color: Colors.grey, size: 20),
|
|
const SizedBox(width: 8),
|
|
Text('$label: ', style: const TextStyle(fontSize: 14, color: Colors.grey)),
|
|
Expanded(
|
|
child: Text(
|
|
value,
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
color: valueColor,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
/// 底部构建带图标的提示信息行
|
|
Widget _buildInfoItem(IconData icon, String text) {
|
|
return Row(
|
|
children: [
|
|
Icon(icon, color: Colors.blue, size: 20),
|
|
const SizedBox(width: 8),
|
|
Text(text, style: const TextStyle(fontSize: 14, color: Colors.black54)),
|
|
],
|
|
);
|
|
}
|
|
}
|