942 lines
35 KiB
Dart
942 lines
35 KiB
Dart
import 'dart:async';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter/services.dart';
|
||
import 'package:getx_scaffold/getx_scaffold.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/storage_service.dart';
|
||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||
|
||
enum ReservationStatus {
|
||
pending, // 待处理 ( addStatus: 0)
|
||
completed, // 完成 ( addStatus: 1)
|
||
rejected, // 拒绝 ( -1)
|
||
unadded, // 未加 ( 2)
|
||
cancel, // 取消预约
|
||
unknown, // 未知状态
|
||
}
|
||
|
||
class ReservationModel {
|
||
final String id;
|
||
final String stationId;
|
||
final String plateNumber;
|
||
String amount;
|
||
final String time;
|
||
final String contactPerson;
|
||
final String contactPhone;
|
||
ReservationStatus status; // 状态是可变的
|
||
|
||
final String contacts;
|
||
final String phone;
|
||
final String rejectReason;
|
||
final String stationName;
|
||
final String startTime;
|
||
final String endTime;
|
||
final String date;
|
||
final String hydAmount;
|
||
final String state;
|
||
final String stateName;
|
||
final String addStatus;
|
||
final String addStatusName;
|
||
bool hasEdit;
|
||
final String isEdit; // "1" 表示可以修改信息
|
||
|
||
// 新增附件相关字段
|
||
final int isTruckAttachment; // 1为有证件数据 0为缺少
|
||
final bool hasDrivingAttachment; // 是否有行驶证
|
||
final bool hasHydrogenationAttachment; // 是否有加氢证
|
||
|
||
ReservationModel({
|
||
required this.id,
|
||
required this.stationId,
|
||
required this.plateNumber,
|
||
required this.amount,
|
||
required this.time,
|
||
required this.contactPerson,
|
||
required this.contactPhone,
|
||
required this.hasEdit,
|
||
this.status = ReservationStatus.pending,
|
||
required this.contacts,
|
||
required this.phone,
|
||
required this.stationName,
|
||
required this.startTime,
|
||
required this.endTime,
|
||
required this.date,
|
||
required this.hydAmount,
|
||
required this.state,
|
||
required this.stateName,
|
||
required this.addStatus,
|
||
required this.addStatusName,
|
||
required this.rejectReason,
|
||
required this.isTruckAttachment,
|
||
required this.hasDrivingAttachment,
|
||
required this.hasHydrogenationAttachment,
|
||
required this.isEdit,
|
||
});
|
||
|
||
/// 工厂构造函数,用于从JSON创建ReservationModel实例
|
||
factory ReservationModel.fromJson(Map<String, dynamic> json) {
|
||
// 1完成 2未加 -1拒绝 0是待加氢
|
||
ReservationStatus currentStatus;
|
||
int statusFromServer = json['addStatus'] as int? ?? 0;
|
||
int state = json['state'] as int? ?? 0;
|
||
if (state == -1) {
|
||
currentStatus = ReservationStatus.rejected;
|
||
} else {
|
||
switch (statusFromServer) {
|
||
case 0:
|
||
currentStatus = ReservationStatus.pending;
|
||
break;
|
||
case 1:
|
||
currentStatus = ReservationStatus.completed;
|
||
break;
|
||
case 2:
|
||
currentStatus = ReservationStatus.unadded;
|
||
break;
|
||
case 6:
|
||
currentStatus = ReservationStatus.cancel;
|
||
break;
|
||
default:
|
||
currentStatus = ReservationStatus.unknown;
|
||
}
|
||
}
|
||
|
||
// 格式化时间显示
|
||
String startTimeStr = json['startTime']?.toString() ?? '';
|
||
String endTimeStr = json['endTime']?.toString() ?? '';
|
||
String dateStr = json['date']?.toString() ?? '';
|
||
String timeRange =
|
||
(startTimeStr.isNotEmpty && endTimeStr.isNotEmpty && dateStr.isNotEmpty)
|
||
? '$dateStr ${startTimeStr.substring(11, 16)}-${endTimeStr.substring(11, 16)}' // 截取 HH:mm
|
||
: '时间未定';
|
||
|
||
// 解析附件信息
|
||
Map<String, dynamic> attachmentVo = json['truckAttachmentVo'] ?? {};
|
||
int isTruckAttachment = attachmentVo['isTruckAttachment'] as int? ?? 0;
|
||
List drivingList = attachmentVo['drivingAttachment'] ?? [];
|
||
List hydrogenationList = attachmentVo['hydrogenationAttachment'] ?? [];
|
||
|
||
return ReservationModel(
|
||
// 原始字段,用于UI兼容
|
||
id: json['id']?.toString() ?? '',
|
||
stationId: json['stationId']?.toString() ?? '',
|
||
plateNumber: json['plateNumber']?.toString() ?? '---',
|
||
amount: '${json['hydAmount']?.toString() ?? '0'}kg',
|
||
time: timeRange,
|
||
contactPerson: json['contacts']?.toString() ?? '无联系人',
|
||
contactPhone: json['phone']?.toString() ?? '无联系电话',
|
||
status: currentStatus,
|
||
|
||
// 新增的完整字段
|
||
contacts: json['contacts']?.toString() ?? '',
|
||
phone: json['phone']?.toString() ?? '',
|
||
stationName: json['stationName']?.toString() ?? '',
|
||
startTime: startTimeStr,
|
||
endTime: endTimeStr,
|
||
date: dateStr,
|
||
hydAmount: json['hydAmount']?.toString() ?? '0',
|
||
state: json['state']?.toString() ?? '',
|
||
addStatus: statusFromServer.toString(),
|
||
addStatusName: json['addStatusName']?.toString() ?? '',
|
||
stateName: json['stateName']?.toString() ?? '',
|
||
rejectReason: json['rejectReason']?.toString() ?? '',
|
||
hasEdit: true,
|
||
isTruckAttachment: isTruckAttachment,
|
||
hasDrivingAttachment: drivingList.isNotEmpty,
|
||
hasHydrogenationAttachment: hydrogenationList.isNotEmpty,
|
||
isEdit: json['isEdit']?.toString() ?? '0',
|
||
);
|
||
}
|
||
}
|
||
|
||
class SiteController extends GetxController with BaseControllerMixin {
|
||
@override
|
||
String get builderId => 'site';
|
||
|
||
SiteController();
|
||
|
||
/// 状态变量:是否有预约数据
|
||
bool hasReservationData = false;
|
||
|
||
// 新增预约数据列表
|
||
List<ReservationModel> reservationList = [];
|
||
Timer? _refreshTimer;
|
||
|
||
final TextEditingController searchController = TextEditingController();
|
||
bool isNotice = false;
|
||
final RefreshController refreshController = RefreshController(initialRefresh: false);
|
||
|
||
// 加氢枪列表
|
||
final RxList<String> gasGunList = <String>[].obs;
|
||
|
||
@override
|
||
bool get listenLifecycleEvent => true;
|
||
|
||
@override
|
||
void onInit() {
|
||
super.onInit();
|
||
renderData();
|
||
msgNotice();
|
||
startAutoRefresh();
|
||
fetchGasGunList();
|
||
}
|
||
|
||
@override
|
||
void onPaused() {
|
||
stopAutoRefresh();
|
||
super.onPaused();
|
||
}
|
||
|
||
@override
|
||
void onClose() {
|
||
stopAutoRefresh();
|
||
searchController.dispose();
|
||
super.onClose();
|
||
}
|
||
|
||
Future<void> msgNotice() async {
|
||
final Map<String, dynamic> requestData = {
|
||
'appFlag': 1,
|
||
'isRead': 1,
|
||
'pageNum': 1,
|
||
'pageSize': 5,
|
||
};
|
||
final response = await HttpService.to.get(
|
||
'appointment/unread_notice/page',
|
||
params: requestData,
|
||
);
|
||
if (response != null) {
|
||
final result = BaseModel.fromJson(response.data);
|
||
if (result.code == 0 && result.data != null) {
|
||
String total = result.data["total"].toString();
|
||
isNotice = int.parse(total) > 0;
|
||
updateUi();
|
||
}
|
||
}
|
||
}
|
||
|
||
void startAutoRefresh() {
|
||
// 先停止已存在的定时器,防止重复启动
|
||
stopAutoRefresh();
|
||
|
||
// 创建一个每5分钟执行一次的周期性定时器
|
||
_refreshTimer = Timer.periodic(const Duration(minutes: 5), (timer) {
|
||
renderData();
|
||
});
|
||
}
|
||
|
||
void onRefresh() => renderData(isRefresh: true);
|
||
|
||
///停止定时器的方法
|
||
void stopAutoRefresh() {
|
||
// 如果定时器存在并且是激活状态,就取消它
|
||
_refreshTimer?.cancel();
|
||
_refreshTimer = null; // 置为null,方便判断
|
||
print("【自动刷新】定时器已停止。");
|
||
}
|
||
|
||
/// 获取加氢枪列表
|
||
Future<void> fetchGasGunList() async {
|
||
try {
|
||
var response = await HttpService.to.get(
|
||
'appointment/station/getGasGunList?hydrogenId=${StorageService.to.userId}',
|
||
);
|
||
if (response != null && response.data != null) {
|
||
final result = BaseModel<dynamic>.fromJson(response.data);
|
||
if (result.code == 0 && result.data != null) {
|
||
List dataList = result.data as List;
|
||
gasGunList.assignAll(dataList.map((e) => e['deviceName'].toString()).toList());
|
||
}
|
||
}
|
||
} catch (e) {
|
||
Logger.d("获取加氢枪列表失败: $e");
|
||
}
|
||
}
|
||
|
||
/// 获取预约数据的方法
|
||
Future<void> fetchReservationData() async {
|
||
showLoading("加载中");
|
||
|
||
final String searchText = searchController.text.trim();
|
||
|
||
try {
|
||
var response = await HttpService.to.post(
|
||
"appointment/orderAddHyd/sitOrderPage",
|
||
data: {
|
||
'stationName': name, // 使用从 renderData 中获取到的 name
|
||
'pageNum': 1,
|
||
'pageSize': 50, // 暂时不考虑分页,一次获取30条
|
||
'keyword': searchText, // 加氢站名称、手机号
|
||
'stationId': StorageService.to.userId,
|
||
},
|
||
);
|
||
|
||
// 安全校验
|
||
if (response == null || response.data == null) {
|
||
showToast('暂时无法获取预约数据');
|
||
hasReservationData = false;
|
||
reservationList = [];
|
||
dismissLoading();
|
||
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'] ?? [];
|
||
|
||
// 使用 .map() 遍历列表,将每个 item 转换为一个 ReservationModel 对象
|
||
reservationList = listFromServer.map((item) {
|
||
return ReservationModel.fromJson(item as Map<String, dynamic>);
|
||
}).toList();
|
||
|
||
// 根据列表是否为空来更新 hasReservationData 状态
|
||
hasReservationData = reservationList.isNotEmpty;
|
||
} else {
|
||
// 接口返回业务错误
|
||
showToast(baseModel.message);
|
||
hasReservationData = false;
|
||
reservationList = []; // 清空列表
|
||
}
|
||
} catch (e) {
|
||
// 捕获网络或解析异常
|
||
showToast('获取预约数据失败');
|
||
hasReservationData = false;
|
||
reservationList = []; // 清空列表
|
||
} finally {
|
||
// 无论成功失败,最后都要关闭加载动画并更新UI
|
||
dismissLoading();
|
||
updateUi();
|
||
}
|
||
}
|
||
|
||
/// 确认预约弹窗重构
|
||
Future<void> confirmReservation(String id, {bool isEdit = false}) async {
|
||
final item = reservationList.firstWhere(
|
||
(item) => item.id == id,
|
||
orElse: () => throw Exception('Reservation not found'),
|
||
);
|
||
|
||
// 加氢量保留3位小数
|
||
double initialAmount = double.tryParse(item.hydAmount) ?? 0.0;
|
||
final TextEditingController amountController = TextEditingController(
|
||
text: initialAmount.toStringAsFixed(3),
|
||
);
|
||
|
||
final RxString selectedGun = (gasGunList.isNotEmpty ? gasGunList.first : '').obs;
|
||
final RxBool isOfflineChecked = false.obs;
|
||
|
||
Get.dialog(
|
||
Dialog(
|
||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||
child: SingleChildScrollView(
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(20.0),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
isEdit ? '修改加氢量' : '确认加氢状态',
|
||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||
),
|
||
const SizedBox(height: 16),
|
||
|
||
// 车牌号及标签
|
||
Row(
|
||
children: [
|
||
Text(
|
||
item.plateNumber == "---" ? '-------' : item.plateNumber,
|
||
style: TextStyle(
|
||
fontSize: 16.sp,
|
||
fontWeight: FontWeight.w500,
|
||
color: item.plateNumber == "---" ? Colors.grey : Colors.black,
|
||
letterSpacing: item.plateNumber == "---" ? 2 : 0,
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Container(
|
||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||
decoration: BoxDecoration(
|
||
color: Color.fromRGBO(232, 243, 255, 1),
|
||
borderRadius: BorderRadius.circular(4),
|
||
),
|
||
child: Text(
|
||
item.plateNumber == "---" ? '车牌号识别' : '重新识别',
|
||
style: TextStyle(
|
||
color: Color.fromRGBO(22, 93, 255, 1),
|
||
fontSize: 13.sp,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
),
|
||
SizedBox(width: 16.w),
|
||
if (item.plateNumber != "---" && item.hasDrivingAttachment)
|
||
_buildInfoTag('行驶证'),
|
||
if (item.plateNumber != "---" && item.hasHydrogenationAttachment)
|
||
_buildInfoTag('加氢证'),
|
||
],
|
||
),
|
||
|
||
const SizedBox(height: 12),
|
||
|
||
// 提示逻辑
|
||
if (isEdit)
|
||
const Text(
|
||
'每个订单只能修改一次,请确认加氢量准确无误',
|
||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||
)
|
||
else
|
||
if (item.plateNumber == "---" || item.isTruckAttachment == 0)
|
||
Row(
|
||
children: [
|
||
const Expanded(
|
||
child: Text(
|
||
'车辆未上传加氢证,请完成线下登记',
|
||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||
),
|
||
),
|
||
Obx(
|
||
() =>
|
||
Checkbox(
|
||
value: isOfflineChecked.value,
|
||
onChanged: (v) => isOfflineChecked.value = v ?? false,
|
||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||
activeColor: AppTheme.themeColor,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
|
||
const SizedBox(height: 16),
|
||
|
||
// 预定加氢量输入区
|
||
Container(
|
||
padding: const EdgeInsets.all(16),
|
||
decoration: BoxDecoration(
|
||
color: const Color(0xFFF7F8FA),
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
'预定加氢量',
|
||
style: TextStyle(
|
||
color: Color.fromRGBO(51, 51, 51, 1),
|
||
fontSize: 14.sp,
|
||
fontWeight: FontWeight.w500,
|
||
),
|
||
),
|
||
const SizedBox(height: 4),
|
||
Row(
|
||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||
textBaseline: TextBaseline.alphabetic,
|
||
children: [
|
||
IntrinsicWidth(
|
||
child: TextField(
|
||
controller: amountController,
|
||
keyboardType: const TextInputType.numberWithOptions(
|
||
decimal: true,
|
||
),
|
||
inputFormatters: [
|
||
// 限制最多输入3位小数
|
||
FilteringTextInputFormatter.allow(
|
||
RegExp(r'^\d+\.?\d{0,3}'),
|
||
),
|
||
],
|
||
style: const TextStyle(
|
||
fontSize: 24,
|
||
fontWeight: FontWeight.bold,
|
||
color: Color(0xFF017143),
|
||
),
|
||
decoration: const InputDecoration(
|
||
enabledBorder: UnderlineInputBorder(
|
||
borderSide: BorderSide(
|
||
color: Color(0xFF017143),
|
||
),
|
||
),
|
||
focusedBorder: const UnderlineInputBorder(
|
||
borderSide: BorderSide(
|
||
color: Color(0xFF017143),
|
||
),
|
||
),
|
||
isDense: true,
|
||
contentPadding: EdgeInsets.zero,
|
||
),
|
||
),
|
||
),
|
||
const Text(
|
||
' KG',
|
||
style: TextStyle(color: Colors.grey, fontSize: 14),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
Container(
|
||
padding: const EdgeInsets.symmetric(
|
||
horizontal: 12,
|
||
vertical: 8,
|
||
),
|
||
decoration: BoxDecoration(
|
||
color: const Color(0xFF017143),
|
||
borderRadius: BorderRadius.circular(8),
|
||
),
|
||
child: const Row(
|
||
children: [
|
||
Icon(Icons.qr_code_scanner, color: Colors.white, size: 18),
|
||
SizedBox(width: 4),
|
||
Text(
|
||
'识别',
|
||
style: TextStyle(color: Colors.white, fontSize: 14),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
|
||
const SizedBox(height: 16),
|
||
|
||
// 加氢枪号选择
|
||
const Text(
|
||
'请选择加氢枪号',
|
||
style: TextStyle(color: Colors.grey, fontSize: 12),
|
||
),
|
||
const SizedBox(height: 8),
|
||
Obx(
|
||
() =>
|
||
Container(
|
||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||
decoration: BoxDecoration(
|
||
border: Border.all(color: Colors.grey.shade300),
|
||
borderRadius: BorderRadius.circular(8),
|
||
),
|
||
child: DropdownButtonHideUnderline(
|
||
child: DropdownButton<String>(
|
||
value: selectedGun.value.isEmpty ? null : selectedGun.value,
|
||
isExpanded: true,
|
||
hint: const Text('请选择加氢枪号'),
|
||
items: gasGunList.map((String gun) {
|
||
return DropdownMenuItem<String>(
|
||
value: gun, child: Text(gun));
|
||
}).toList(),
|
||
onChanged: (v) => selectedGun.value = v ?? '',
|
||
),
|
||
),
|
||
),
|
||
),
|
||
|
||
const SizedBox(height: 24),
|
||
|
||
// 按钮
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
flex: 2,
|
||
child: ElevatedButton(
|
||
onPressed: () {
|
||
//加氢后 订单编辑
|
||
if (isEdit) {
|
||
final num addHydAmount =
|
||
num.tryParse(amountController.text) ?? 0;
|
||
upDataService(
|
||
id,
|
||
0,
|
||
1,
|
||
addHydAmount,
|
||
"",
|
||
item,
|
||
gunNumber: selectedGun.value,
|
||
plateNumber: item.plateNumber,
|
||
isEdit: true
|
||
);
|
||
return;
|
||
}
|
||
//订单确认
|
||
if (!isEdit &&
|
||
(item.plateNumber == "---" ||
|
||
item.isTruckAttachment == 0) &&
|
||
!isOfflineChecked.value) {
|
||
showToast("车辆未上传加氢证 , 请确保线下登记后点击确认");
|
||
return;
|
||
}
|
||
if (selectedGun.value.isEmpty) {
|
||
showToast("请选择加氢枪号");
|
||
return;
|
||
}
|
||
Get.back();
|
||
final num addHydAmount =
|
||
num.tryParse(amountController.text) ?? 0;
|
||
upDataService(
|
||
id,
|
||
0,
|
||
1,
|
||
addHydAmount,
|
||
"",
|
||
item,
|
||
gunNumber: selectedGun.value,
|
||
plateNumber: item.plateNumber,
|
||
);
|
||
},
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: const Color(0xFF017143),
|
||
minimumSize: const Size(double.infinity, 48),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(8),
|
||
),
|
||
elevation: 0,
|
||
),
|
||
child: Text(
|
||
isEdit ? '确认修改' : '确认加氢',
|
||
style: const TextStyle(color: Colors.white, fontSize: 16),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(width: 12),
|
||
Expanded(
|
||
flex: 1,
|
||
child: OutlinedButton(
|
||
onPressed: () {
|
||
Get.back();
|
||
if (!isEdit) {
|
||
upDataService(
|
||
id,
|
||
0,
|
||
2,
|
||
0,
|
||
"",
|
||
item,
|
||
gunNumber: selectedGun.value,
|
||
plateNumber: item.plateNumber,
|
||
);
|
||
}
|
||
},
|
||
style: OutlinedButton.styleFrom(
|
||
minimumSize: const Size(double.infinity, 48),
|
||
side: BorderSide(color: Colors.grey.shade300),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(8),
|
||
),
|
||
),
|
||
child: Text(
|
||
isEdit ? '取消' : '未加氢',
|
||
style: const TextStyle(color: Colors.grey, fontSize: 16),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
|
||
const SizedBox(height: 12),
|
||
Row(
|
||
children: [
|
||
const Expanded(
|
||
child: Divider(color: Color(0xFFEEEEEE), thickness: 1),
|
||
),
|
||
Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||
child: GestureDetector(
|
||
onTap: () => Get.back(),
|
||
child: Text(
|
||
'暂不处理',
|
||
style: TextStyle(
|
||
color: Color.fromRGBO(16, 185, 129, 1),
|
||
fontSize: 14.sp,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
const Expanded(
|
||
child: Divider(color: Color(0xFFEEEEEE), thickness: 1),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
barrierDismissible: true,
|
||
);
|
||
}
|
||
|
||
Widget _buildInfoTag(String label) {
|
||
return Container(
|
||
margin: const EdgeInsets.only(left: 4),
|
||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||
decoration: BoxDecoration(
|
||
color: const Color(0xFFF2F3F5),
|
||
borderRadius: BorderRadius.circular(4),
|
||
),
|
||
child: Text(
|
||
label,
|
||
style: TextStyle(color: Color(0xFF999999), fontSize: 11.sp),
|
||
),
|
||
);
|
||
}
|
||
|
||
Future<void> rejectReservation(String id) async {
|
||
final item = reservationList.firstWhere((item) => item.id == id);
|
||
final TextEditingController reasonController = TextEditingController();
|
||
final RxString selectedReason = ''.obs;
|
||
|
||
// 预设的拒绝原因列表
|
||
final List<String> presetReasons = ['车辆未到场', '司机联系不上', '设备故障无法加氢'];
|
||
|
||
Get.dialog(
|
||
Dialog(
|
||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||
child: SingleChildScrollView(
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(24.0),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
children: [
|
||
const Text(
|
||
'拒绝预约',
|
||
textAlign: TextAlign.center,
|
||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||
),
|
||
const SizedBox(height: 16),
|
||
Text(
|
||
'正在处理车牌号 ${item.plateNumber} 的预约',
|
||
textAlign: TextAlign.center,
|
||
style: const TextStyle(fontSize: 16, color: AppTheme.themeColor),
|
||
),
|
||
const SizedBox(height: 24),
|
||
|
||
// 4. 预设原因选择区域
|
||
const Text('选择或填写拒绝原因:', style: TextStyle(color: Colors.grey)),
|
||
const SizedBox(height: 8),
|
||
Obx(
|
||
() =>
|
||
Wrap(
|
||
// 使用 Wrap 自动换行
|
||
spacing: 8.0, // 水平间距
|
||
children: presetReasons.map((reason) {
|
||
final isSelected = selectedReason.value == reason;
|
||
return ChoiceChip(
|
||
label: Text(reason),
|
||
selected: isSelected,
|
||
onSelected: (selected) {
|
||
if (selected) {
|
||
selectedReason.value = reason;
|
||
reasonController.clear(); // 选择预设原因时,清空自定义输入
|
||
}
|
||
},
|
||
selectedColor: Get.theme.primaryColor.withOpacity(0.2),
|
||
labelStyle: TextStyle(
|
||
color: isSelected ? Get.theme.primaryColor : Colors.black,
|
||
),
|
||
);
|
||
}).toList(),
|
||
),
|
||
),
|
||
const SizedBox(height: 16),
|
||
|
||
// 5. 自定义原因输入框
|
||
TextField(
|
||
controller: reasonController,
|
||
maxLines: 2,
|
||
decoration: InputDecoration(
|
||
hintText: '输入其它原因',
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(8),
|
||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||
),
|
||
),
|
||
onChanged: (text) {
|
||
if (text.isNotEmpty) {
|
||
selectedReason.value = ''; // 输入自定义原因时,取消预设选择
|
||
}
|
||
},
|
||
),
|
||
const SizedBox(height: 24),
|
||
|
||
// 6. 按钮区域
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: TextButton(
|
||
onPressed: () {
|
||
// 获取最终的拒绝原因
|
||
String finalReason = reasonController.text.trim();
|
||
if (finalReason.isEmpty) {
|
||
finalReason = selectedReason.value;
|
||
}
|
||
|
||
if (finalReason.isEmpty) {
|
||
showToast('请选择或填写一个拒绝原因');
|
||
return;
|
||
}
|
||
|
||
Get.back(); // 关闭弹窗
|
||
upDataService(
|
||
id,
|
||
1,
|
||
-1,
|
||
0,
|
||
finalReason,
|
||
item,
|
||
plateNumber: item.plateNumber,
|
||
);
|
||
},
|
||
child: const Text('确认拒绝', style: TextStyle(color: Colors
|
||
.red)),
|
||
),
|
||
),
|
||
const SizedBox(width: 16),
|
||
Expanded(
|
||
child: TextButton(
|
||
onPressed: () => Get.back(),
|
||
child: const Text('暂不处理', style: TextStyle(color: Colors
|
||
.grey)),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
barrierDismissible: false,
|
||
);
|
||
}
|
||
|
||
//addStatus 1完成 2未加 -1拒绝
|
||
void upDataService(String id,
|
||
int status,
|
||
int addStatus,
|
||
num addHydAmount,
|
||
String rejectReason,
|
||
ReservationModel item, {
|
||
String? gunNumber,
|
||
String? plateNumber, bool isEdit = false
|
||
}) async {
|
||
showLoading("确认中");
|
||
|
||
try {
|
||
var responseData;
|
||
if (isEdit) {
|
||
responseData = await HttpService.to.post(
|
||
'appointment/orderAddHyd/modifyOrder',
|
||
data: {
|
||
'id': id,
|
||
"addHydAmount": addHydAmount,
|
||
"plateNumber": plateNumber,
|
||
if (gunNumber != null && gunNumber.isNotEmpty) "gunNumber": gunNumber,
|
||
},
|
||
);
|
||
}else if (addStatus == -1) {
|
||
responseData = await HttpService.to.post(
|
||
'appointment/orderAddHyd/rejectOrder',
|
||
data: {
|
||
'id': id,
|
||
'state': -1, //拒绝使用
|
||
"rejectReason": rejectReason,
|
||
"plateNumber": plateNumber,
|
||
if (gunNumber != null && gunNumber.isNotEmpty) "gunNumber": gunNumber,
|
||
},
|
||
);
|
||
} else {
|
||
responseData = await HttpService.to.post(
|
||
'appointment/orderAddHyd/completeOrder',
|
||
data: {
|
||
'id': id,
|
||
'addStatus': addStatus, //完成使用 完成1,未加2
|
||
"addHydAmount": addHydAmount,
|
||
"plateNumber": plateNumber,
|
||
if (gunNumber != null && gunNumber.isNotEmpty) "gunNumber": gunNumber,
|
||
},
|
||
);
|
||
}
|
||
|
||
if (responseData == null || responseData.data == null) {
|
||
dismissLoading();
|
||
showToast('服务暂不可用,请稍后');
|
||
return;
|
||
}
|
||
var result = BaseModel.fromJson(responseData.data);
|
||
if (result.code == 0) {
|
||
showSuccessToast("操作成功");
|
||
} else {
|
||
showToast(result.message);
|
||
}
|
||
dismissLoading();
|
||
|
||
//1完成 2未加 -1拒绝
|
||
if (addStatus == 1) {
|
||
item.status = ReservationStatus.completed;
|
||
item.amount = "${addHydAmount}kg";
|
||
} else if (addStatus == -1) {
|
||
item.status = ReservationStatus.rejected;
|
||
} else if (addStatus == 2) {
|
||
item.status = ReservationStatus.unadded;
|
||
}
|
||
renderData();
|
||
} catch (e) {
|
||
dismissLoading();
|
||
}
|
||
}
|
||
|
||
String leftHydrogen = "";
|
||
String orderAmount = "";
|
||
String completedAmount = "";
|
||
String name = "";
|
||
String orderTotalAmount = "";
|
||
String orderUnfinishedAmount = "";
|
||
|
||
Future<void> renderData({bool isRefresh = false}) async {
|
||
try {
|
||
var responseData = await HttpService.to.get(
|
||
'appointment/station/getStationInfoById?hydrogenId=${StorageService.to.userId}',
|
||
);
|
||
|
||
if (responseData == null || responseData.data == null) {
|
||
showToast('暂时无法获取站点信息');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
var result = BaseModel.fromJson(responseData.data);
|
||
|
||
leftHydrogen = result.data["leftHydrogen"] ?? "";
|
||
orderAmount = result.data["orderAmount"].toString();
|
||
completedAmount = result.data["completedAmount"].toString();
|
||
name = result.data["name"].toString();
|
||
orderTotalAmount = result.data["orderTotalAmount"].toString();
|
||
orderUnfinishedAmount = result.data["orderUnfinishedAmount"].toString();
|
||
|
||
leftHydrogen = leftHydrogen.isEmpty ? "统计中" : leftHydrogen.toString();
|
||
orderTotalAmount =
|
||
orderTotalAmount.isEmpty ? "统计中" : orderTotalAmount.toString();
|
||
orderUnfinishedAmount = orderUnfinishedAmount.isEmpty
|
||
? "统计中"
|
||
: orderUnfinishedAmount.toString();
|
||
} catch (e) {
|
||
showToast('数据异常');
|
||
}
|
||
} catch (e) {} finally {
|
||
//加载列表数据
|
||
fetchReservationData();
|
||
|
||
if (isRefresh) {
|
||
refreshController.refreshCompleted();
|
||
}
|
||
}
|
||
}
|
||
}
|