476 lines
15 KiB
Dart
476 lines
15 KiB
Dart
import 'dart:async';
|
||
|
||
import 'package:flutter/cupertino.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:get/get.dart';
|
||
import 'package:getx_scaffold/getx_scaffold.dart';
|
||
import 'package:intl/intl.dart';
|
||
import 'package:ln_jq_app/common/model/base_model.dart';
|
||
import 'package:ln_jq_app/pages/login/view.dart';
|
||
|
||
import '../../../common/styles/theme.dart';
|
||
import '../../../storage_service.dart';
|
||
|
||
class ReservationController extends GetxController with BaseControllerMixin {
|
||
@override
|
||
String get builderId => 'b_reservation';
|
||
|
||
final List<String> operationStatusOptions = ["营运中", "维修中", "暂停营业", "站点关闭"];
|
||
String selectedOperationStatus = "营运中";
|
||
|
||
// --- 其它状态下的时间选择 ---
|
||
DateTime? customStartTime;
|
||
DateTime? customEndTime;
|
||
|
||
String get customStartTimeStr => customStartTime != null
|
||
? DateFormat('yyyy-MM-dd HH:mm').format(customStartTime!)
|
||
: '点击选择开始时间';
|
||
|
||
String get customEndTimeStr => customEndTime != null
|
||
? DateFormat('yyyy-MM-dd HH:mm').format(customEndTime!)
|
||
: '点击选择结束时间';
|
||
|
||
// --- 站点广播相关 ---
|
||
final TextEditingController broadcastTitleController = TextEditingController();
|
||
final TextEditingController broadcastContentController = TextEditingController();
|
||
final RxInt selectedTabIndex = 0.obs;
|
||
|
||
@override
|
||
bool get listenLifecycleEvent => true;
|
||
|
||
@override
|
||
void onInit() {
|
||
super.onInit();
|
||
// 1. 初始化默认时间
|
||
customStartTime = DateTime.now();
|
||
customEndTime = customStartTime!.add(const Duration(days: 1));
|
||
renderData();
|
||
startAutoRefresh();
|
||
}
|
||
|
||
@override
|
||
void onPaused() {
|
||
stopAutoRefresh();
|
||
super.onPaused();
|
||
}
|
||
|
||
@override
|
||
void onClose() {
|
||
stopAutoRefresh();
|
||
broadcastTitleController.dispose();
|
||
broadcastContentController.dispose();
|
||
super.onClose();
|
||
}
|
||
|
||
void startAutoRefresh() {
|
||
// 先停止已存在的定时器,防止重复启动
|
||
stopAutoRefresh();
|
||
|
||
// 创建一个每5分钟执行一次的周期性定时器
|
||
_refreshTimer = Timer.periodic(const Duration(minutes: 5), (timer) {
|
||
renderData();
|
||
});
|
||
}
|
||
|
||
///停止定时器的方法
|
||
void stopAutoRefresh() {
|
||
// 如果定时器存在并且是激活状态,就取消它
|
||
_refreshTimer?.cancel();
|
||
_refreshTimer = null; // 置为null,方便判断
|
||
}
|
||
|
||
String name = "";
|
||
String address = "";
|
||
String phone = "";
|
||
String costPrice = "";
|
||
String customerPrice = "";
|
||
String startBusiness = "";
|
||
String endBusiness = "";
|
||
String timeStr = "";
|
||
String operatingEnterprise = "";
|
||
String hydrogenId = "";
|
||
|
||
String jobTipStr = "";
|
||
String jobDetailsStr = "";
|
||
String jobId = "";
|
||
Timer? _refreshTimer;
|
||
|
||
Future<void> renderData() async {
|
||
showLoading("加载中");
|
||
try {
|
||
//获取加氢站未执行的状态修改任务信息
|
||
var jobData = await HttpService.to.get('appointment/job/hyd/un-executed');
|
||
if (jobData != null) {
|
||
final jobDataResult = BaseModel.fromJson(jobData.data);
|
||
if (jobDataResult.code == 0) {
|
||
try {
|
||
final List<dynamic> dataList = jobDataResult.data is List
|
||
? jobDataResult.data
|
||
: [];
|
||
final firstJob = dataList[0];
|
||
|
||
jobId = firstJob["id"] ?? "";
|
||
String endTime = firstJob["endTime"] ?? "";
|
||
String beginTime = firstJob["beginTime"] ?? "";
|
||
String hydStatus = firstJob["hydStatus"].toString() ?? "";
|
||
String hydStatusStr = "";
|
||
if (hydStatus == "0") {
|
||
hydStatusStr = "营运中";
|
||
} else if (hydStatus == "1") {
|
||
hydStatusStr = "维修中";
|
||
} else if (hydStatus == "2") {
|
||
hydStatusStr = "站点关闭";
|
||
} else if (hydStatus == "3") {
|
||
hydStatusStr = "暂停营业";
|
||
}
|
||
|
||
//现在的时间晚于开始时间就不显示文案
|
||
bool isJobStarted = false;
|
||
try {
|
||
if (beginTime.isNotEmpty) {
|
||
DateTime beginDateTime = DateTime.parse(beginTime);
|
||
if (DateTime.now().isAfter(beginDateTime)) {
|
||
isJobStarted = true;
|
||
}
|
||
}
|
||
} catch (e) {
|
||
print("开始时间解析失败: $e");
|
||
}
|
||
if (isJobStarted) {
|
||
jobTipStr = "";
|
||
}
|
||
|
||
//结束时间
|
||
if (endTime.isNotEmpty) {
|
||
try {
|
||
// 解析时间字符串
|
||
DateTime endDateTime = DateTime.parse(endTime);
|
||
DateTime beginDateTime = DateTime.parse(beginTime);
|
||
DateTime now = DateTime.now(); //计算时间差 (endTime - now)
|
||
Duration diff = endDateTime.difference(now);
|
||
|
||
// 计算小时数 (允许小数,例如 0.5)
|
||
// inMinutes / 60 可以得到更精确的小数小时
|
||
double hoursLeft = diff.inMinutes / 60.0;
|
||
|
||
//计算当前时间-开始时间
|
||
Duration startDiff = beginDateTime.difference(now);
|
||
double hoursUntilStart = startDiff.inMinutes / 60.0;
|
||
|
||
|
||
// 只有在【当前时间早于开始时间】且【剩余时间大于0】时才显示文案
|
||
if (now.isBefore(beginDateTime) && hoursLeft > 0) {
|
||
// 如果是正数,表示还有多久结束
|
||
String timeTip = " ${hoursUntilStart.toStringAsFixed(2)}小时后";
|
||
jobTipStr = "$timeTip$hydStatusStr";
|
||
} else {
|
||
jobTipStr = "";
|
||
}
|
||
|
||
jobDetailsStr =
|
||
"当前站点已设置$beginTime至$endTime,共${hoursLeft.toStringAsFixed(2)}小时,为$hydStatusStr状态";
|
||
|
||
// 如果是处于非营运状态,自动回填开始和结束时间
|
||
// 假设 customStartTime 是现在,customEndTime 是接口返回的结束时间
|
||
customStartTime = beginDateTime;
|
||
customEndTime = endDateTime;
|
||
} catch (e) {
|
||
print("时间解析失败: $e");
|
||
}
|
||
}
|
||
} catch (e) {
|
||
Logger.d("解析失败或者没返回信息: $e");
|
||
|
||
jobTipStr = "";
|
||
}
|
||
}
|
||
}
|
||
|
||
//获取站点信息
|
||
var responseData = await HttpService.to.get(
|
||
'appointment/station/getStationInfoById?hydrogenId=${StorageService.to.userId}',
|
||
);
|
||
|
||
if (responseData == null && responseData!.data == null) {
|
||
dismissLoading();
|
||
showToast('暂时无法获取站点信息');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
var result = BaseModel.fromJson(responseData.data);
|
||
name = result.data["name"] ?? "";
|
||
hydrogenId = result.data["hydrogenId"].toString();
|
||
address = result.data["address"] ?? "";
|
||
|
||
var rawCostPrice = result.data["costPrice"];
|
||
costPrice = (rawCostPrice != null && rawCostPrice.toString().isNotEmpty)
|
||
? "¥$rawCostPrice"
|
||
: "暂无价格";
|
||
|
||
var customerPriceTemp = result.data["customerPrice"];
|
||
customerPrice =
|
||
(customerPriceTemp != null && customerPriceTemp.toString().isNotEmpty)
|
||
? "$customerPriceTemp"
|
||
: "暂无价格";
|
||
|
||
phone = result.data["phone"] ?? "";
|
||
startBusiness = result.data["startBusiness"] ?? "";
|
||
endBusiness = result.data["endBusiness"] ?? "";
|
||
operatingEnterprise = result.data["operatingEnterprise"].toString();
|
||
|
||
String temp = result.data["siteStatusName"].toString();
|
||
selectedOperationStatus = (temp.isEmpty || temp == "null") ? "营运中" : temp;
|
||
|
||
if (startBusiness.isNotEmpty && endBusiness.isNotEmpty) {
|
||
if (startBusiness == "00:00:00" && endBusiness == "23:59:59") {
|
||
timeStr = "24小时营业";
|
||
} else {
|
||
timeStr = '${startBusiness.substring(0, 5)} - ${endBusiness.substring(0, 5)}';
|
||
}
|
||
} else {
|
||
timeStr = "时间未设置";
|
||
}
|
||
|
||
operatingEnterprise = operatingEnterprise.isEmpty ? "暂未设置" : operatingEnterprise;
|
||
|
||
dismissLoading();
|
||
} catch (e) {
|
||
dismissLoading();
|
||
showToast('数据异常');
|
||
}
|
||
} catch (e) {
|
||
dismissLoading();
|
||
} finally {
|
||
updateUi();
|
||
}
|
||
}
|
||
|
||
void onOperationStatusChanged(String? newValue) {
|
||
if (newValue != null) {
|
||
selectedOperationStatus = newValue;
|
||
updateUi();
|
||
}
|
||
}
|
||
|
||
/// 使用底部滚轮形式选择时间(下拉框效果)
|
||
void pickDateTime(BuildContext context, bool isStart) {
|
||
DateTime now = DateTime.now();
|
||
DateTime initialDate = isStart ? (customStartTime ?? now) : (customEndTime ?? now);
|
||
|
||
DateTime minLimit = isStart
|
||
? now.subtract(const Duration(minutes: 1))
|
||
: (customStartTime ?? now).subtract(const Duration(minutes: 1));
|
||
|
||
if (initialDate.isBefore(minLimit)) {
|
||
initialDate = isStart ? now : (customStartTime ?? now);
|
||
}
|
||
|
||
DateTime tempDate = initialDate;
|
||
|
||
Get.bottomSheet(
|
||
Container(
|
||
height: 300,
|
||
decoration: const BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(16),
|
||
topRight: Radius.circular(16),
|
||
),
|
||
),
|
||
child: Column(
|
||
children: [
|
||
Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
CupertinoButton(
|
||
onPressed: () => Get.back(),
|
||
child: const Text('取消', style: TextStyle(color: Colors.grey)),
|
||
),
|
||
CupertinoButton(
|
||
onPressed: () {
|
||
if (isStart) {
|
||
customStartTime = tempDate;
|
||
if (customEndTime != null &&
|
||
customEndTime!.isBefore(customStartTime!)) {
|
||
customEndTime = customStartTime!.add(const Duration(days: 1));
|
||
}
|
||
} else {
|
||
if (tempDate.isBefore(customStartTime ?? DateTime.now())) {
|
||
showToast('结束时间不能早于开始时间');
|
||
return;
|
||
}
|
||
customEndTime = tempDate;
|
||
}
|
||
updateUi();
|
||
Get.back();
|
||
},
|
||
child: const Text(
|
||
'确定',
|
||
style: TextStyle(
|
||
color: AppTheme.themeColor,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
const Divider(height: 1),
|
||
Expanded(
|
||
child: CupertinoDatePicker(
|
||
mode: CupertinoDatePickerMode.dateAndTime,
|
||
initialDateTime: initialDate,
|
||
minimumDate: minLimit,
|
||
use24hFormat: true,
|
||
onDateTimeChanged: (DateTime newDate) {
|
||
tempDate = newDate;
|
||
},
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
backgroundColor: Colors.transparent,
|
||
);
|
||
}
|
||
|
||
void saveInfo() async {
|
||
if (selectedOperationStatus != "营运中") {
|
||
if (customStartTime == null || customEndTime == null) {
|
||
showToast("请选择开始和结束时间");
|
||
return;
|
||
}
|
||
}
|
||
|
||
showLoading("保存中");
|
||
try {
|
||
var responseData = await HttpService.to.post(
|
||
'appointment/station/updateStationStatus',
|
||
data: {
|
||
'hydrogenId': hydrogenId,
|
||
'name': name,
|
||
'siteStatus': selectedOperationStatus == "营运中"
|
||
? "0"
|
||
: selectedOperationStatus == "维修中"
|
||
? "1"
|
||
: selectedOperationStatus == "站点关闭"
|
||
? "2"
|
||
: selectedOperationStatus == "暂停营业"
|
||
? "3"
|
||
: 0,
|
||
'beginTime': selectedOperationStatus == "营运中"
|
||
? null
|
||
: DateFormat('yyyy-MM-dd HH:mm:ss').format(customStartTime!),
|
||
'endTime': selectedOperationStatus == "营运中"
|
||
? null
|
||
: DateFormat('yyyy-MM-dd HH:mm:ss').format(customEndTime!),
|
||
'updateTime': getNowDateTimeString(),
|
||
},
|
||
);
|
||
|
||
if (responseData == null || responseData.data == null) {
|
||
dismissLoading();
|
||
showToast('服务暂不可用,请稍后');
|
||
return;
|
||
}
|
||
var result = BaseModel.fromJson(responseData.data);
|
||
if (result.code == 0) {
|
||
showSuccessToast("保存成功,已同步通知对应司机");
|
||
|
||
//重新刷新页面
|
||
renderData();
|
||
}
|
||
dismissLoading();
|
||
} catch (e) {
|
||
dismissLoading();
|
||
}
|
||
}
|
||
|
||
/// 显示当前未执行任务的详情弹窗
|
||
void showJob() {
|
||
if (jobDetailsStr.isEmpty) {
|
||
showToast("当前没有正在生效的任务设置");
|
||
return;
|
||
}
|
||
|
||
DialogX.to.showConfirmDialog(
|
||
title: '当前设置详情',
|
||
content: Text(jobDetailsStr, style: const TextStyle(fontSize: 15, height: 1.5)),
|
||
confirmText: '好的',
|
||
cancelText: '取消设置',
|
||
onCancel: () {
|
||
// 点击“取消设置”调用删除接口
|
||
_cancelJob();
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 内部私有方法:调用取消/删除任务接口
|
||
void _cancelJob() async {
|
||
showLoading("正在取消...");
|
||
try {
|
||
var response = await HttpService.to.delete('appointment/job/hyd/$jobId');
|
||
|
||
dismissLoading();
|
||
if (response != null) {
|
||
var result = BaseModel.fromJson(response.data);
|
||
if (result.code == 0) {
|
||
showSuccessToast("已成功取消该设置");
|
||
// 成功后重新刷新页面数据,重置状态
|
||
renderData();
|
||
} else {
|
||
showErrorToast(result.error);
|
||
}
|
||
}
|
||
} catch (e) {
|
||
dismissLoading();
|
||
showErrorToast("取消失败,请稍后重试");
|
||
Logger.d("取消任务失败: $e");
|
||
}
|
||
}
|
||
|
||
/// 发送站点广播
|
||
void sendBroadcast() async {
|
||
String title = broadcastTitleController.text.trim();
|
||
String content = broadcastContentController.text.trim();
|
||
|
||
if (title.isEmpty) {
|
||
showToast("请输入通知标题");
|
||
return;
|
||
}
|
||
if (content.isEmpty) {
|
||
showToast("请输入通知内容");
|
||
return;
|
||
}
|
||
|
||
showLoading("发送中...");
|
||
try {
|
||
var responseData = await HttpService.to.post(
|
||
'appointment/notice/push/station/broadcast',
|
||
data: {'title': title, 'content': content},
|
||
);
|
||
|
||
dismissLoading();
|
||
if (responseData != null) {
|
||
var result = BaseModel.fromJson(responseData.data);
|
||
if (result.code == 0) {
|
||
showSuccessToast("广播发送成功");
|
||
} else {
|
||
showErrorToast(result.error);
|
||
}
|
||
}
|
||
} catch (e) {
|
||
dismissLoading();
|
||
showToast("发送失败,请稍后重试");
|
||
}
|
||
}
|
||
|
||
void logout() async {
|
||
await StorageService.to.clearLoginInfo();
|
||
Get.offAll(() => LoginPage());
|
||
}
|
||
}
|