2026-02-25 15:43:47 +08:00
|
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
|
|
|
|
using CommunityToolkit.Mvvm.Input;
|
|
|
|
|
|
using PetWashControl.Models;
|
|
|
|
|
|
using PetWashControl.Services;
|
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
|
using System.Windows;
|
|
|
|
|
|
|
|
|
|
|
|
namespace PetWashControl.ViewModels;
|
|
|
|
|
|
|
2026-02-25 18:30:24 +08:00
|
|
|
|
public partial class WashStep : ObservableObject
|
|
|
|
|
|
{
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private string _name = "";
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private string _status = "等待中";
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private bool _isActive;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 15:43:47 +08:00
|
|
|
|
public partial class MainViewModel : ObservableObject
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly ApiService _apiService;
|
|
|
|
|
|
private readonly MqttClientService _mqttService;
|
|
|
|
|
|
private readonly ConfigurationService _config;
|
|
|
|
|
|
private readonly LogService _logger;
|
|
|
|
|
|
|
2026-02-25 18:30:24 +08:00
|
|
|
|
public event Action<string>? ViewChanged;
|
|
|
|
|
|
|
2026-02-25 15:43:47 +08:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private ObservableCollection<Package> _packages = new();
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private Package? _selectedPackage;
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private Order? _currentOrder;
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
2026-02-25 18:30:24 +08:00
|
|
|
|
private string _statusMessage = "系统就绪";
|
2026-02-25 15:43:47 +08:00
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private bool _isDoorOpen;
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private bool _isWashing;
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private bool _isConnected;
|
|
|
|
|
|
|
2026-02-25 18:30:24 +08:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private string _currentView = "Idle";
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private int _washProgress;
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private string _currentStep = "";
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private string _remainingTime = "00:00";
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private ObservableCollection<WashStep> _washSteps = new();
|
|
|
|
|
|
|
2026-02-26 11:30:31 +08:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private double _waterTemperature = 40.0;
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
private double _roomTemperature = 25.0;
|
|
|
|
|
|
|
2026-02-25 15:43:47 +08:00
|
|
|
|
public MainViewModel()
|
|
|
|
|
|
{
|
|
|
|
|
|
_config = new ConfigurationService();
|
|
|
|
|
|
_logger = new LogService();
|
|
|
|
|
|
_apiService = new ApiService(_config);
|
|
|
|
|
|
_mqttService = new MqttClientService(_config);
|
|
|
|
|
|
_mqttService.MessageReceived += OnMqttMessageReceived;
|
2026-02-25 18:30:24 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化洗护步骤
|
|
|
|
|
|
InitializeWashSteps();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void InitializeWashSteps()
|
|
|
|
|
|
{
|
|
|
|
|
|
WashSteps.Add(new WashStep { Name = "第一次冲水", Status = "等待中" });
|
|
|
|
|
|
WashSteps.Add(new WashStep { Name = "沐浴露喷洒", Status = "等待中" });
|
|
|
|
|
|
WashSteps.Add(new WashStep { Name = "第二次冲水", Status = "等待中" });
|
|
|
|
|
|
WashSteps.Add(new WashStep { Name = "香波喷洒", Status = "等待中" });
|
|
|
|
|
|
WashSteps.Add(new WashStep { Name = "第三次冲水", Status = "等待中" });
|
|
|
|
|
|
WashSteps.Add(new WashStep { Name = "热风吹毛", Status = "等待中" });
|
|
|
|
|
|
WashSteps.Add(new WashStep { Name = "冷热风混合", Status = "等待中" });
|
2026-02-25 15:43:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async Task InitializeAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInfo("开始初始化系统...");
|
|
|
|
|
|
|
|
|
|
|
|
await _mqttService.ConnectAsync();
|
|
|
|
|
|
IsConnected = _mqttService.IsConnected;
|
|
|
|
|
|
_logger.LogInfo("MQTT连接成功");
|
|
|
|
|
|
|
|
|
|
|
|
await LoadPackagesAsync();
|
2026-02-25 18:30:24 +08:00
|
|
|
|
StatusMessage = "系统就绪,请点击开始";
|
2026-02-25 15:43:47 +08:00
|
|
|
|
_logger.LogInfo("系统初始化完成");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError("初始化失败", ex);
|
|
|
|
|
|
StatusMessage = $"初始化失败: {ex.Message}";
|
|
|
|
|
|
MessageBox.Show($"系统初始化失败,请检查后端服务是否启动。\n\n错误: {ex.Message}",
|
|
|
|
|
|
"错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private async Task LoadPackagesAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInfo("加载套餐列表...");
|
|
|
|
|
|
var packages = await _apiService.GetPackagesAsync();
|
|
|
|
|
|
Packages.Clear();
|
|
|
|
|
|
foreach (var package in packages)
|
|
|
|
|
|
{
|
|
|
|
|
|
Packages.Add(package);
|
|
|
|
|
|
}
|
|
|
|
|
|
_logger.LogInfo($"成功加载 {packages.Count} 个套餐");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError("加载套餐失败", ex);
|
|
|
|
|
|
StatusMessage = $"加载套餐失败: {ex.Message}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 18:30:24 +08:00
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private void ShowPayment()
|
|
|
|
|
|
{
|
|
|
|
|
|
CurrentView = "Payment";
|
|
|
|
|
|
ViewChanged?.Invoke("Payment");
|
|
|
|
|
|
StatusMessage = "请选择套餐";
|
|
|
|
|
|
_logger.LogInfo("切换到支付界面");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-26 11:30:31 +08:00
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private void ShowSettings()
|
|
|
|
|
|
{
|
|
|
|
|
|
CurrentView = "Settings";
|
|
|
|
|
|
ViewChanged?.Invoke("Settings");
|
|
|
|
|
|
StatusMessage = "系统设置";
|
|
|
|
|
|
_logger.LogInfo("切换到设置界面");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 18:30:24 +08:00
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private void BackToIdle()
|
|
|
|
|
|
{
|
|
|
|
|
|
CurrentView = "Idle";
|
|
|
|
|
|
ViewChanged?.Invoke("Idle");
|
|
|
|
|
|
StatusMessage = "系统就绪,请点击开始";
|
|
|
|
|
|
SelectedPackage = null;
|
|
|
|
|
|
CurrentOrder = null;
|
|
|
|
|
|
IsDoorOpen = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 重置洗护步骤状态
|
|
|
|
|
|
foreach (var step in WashSteps)
|
|
|
|
|
|
{
|
|
|
|
|
|
step.Status = "等待中";
|
|
|
|
|
|
step.IsActive = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInfo("返回待机界面");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private async Task SelectPackage(Package package)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (package == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
SelectedPackage = package;
|
|
|
|
|
|
_logger.LogInfo($"选择套餐: {package.Name}");
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建订单
|
|
|
|
|
|
CurrentOrder = await _apiService.CreateOrderAsync(package.Id);
|
|
|
|
|
|
StatusMessage = $"订单创建成功,请扫码支付 ¥{package.Price}";
|
|
|
|
|
|
_logger.LogInfo($"订单创建成功,订单ID: {CurrentOrder?.Id}");
|
|
|
|
|
|
|
|
|
|
|
|
// 切换到二维码支付界面
|
|
|
|
|
|
CurrentView = "QRCode";
|
|
|
|
|
|
ViewChanged?.Invoke("QRCode");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError("创建订单失败", ex);
|
|
|
|
|
|
StatusMessage = $"创建订单失败: {ex.Message}";
|
|
|
|
|
|
MessageBox.Show($"创建订单失败\n\n{ex.Message}", "错误",
|
|
|
|
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private void CancelPayment()
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInfo("取消支付");
|
|
|
|
|
|
CurrentOrder = null;
|
|
|
|
|
|
SelectedPackage = null;
|
|
|
|
|
|
CurrentView = "Payment";
|
|
|
|
|
|
ViewChanged?.Invoke("Payment");
|
|
|
|
|
|
StatusMessage = "已取消支付,请重新选择套餐";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 15:43:47 +08:00
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private async Task CreateOrderAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (SelectedPackage == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("请先选择套餐", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInfo($"创建订单,套餐ID: {SelectedPackage.Id}");
|
|
|
|
|
|
CurrentOrder = await _apiService.CreateOrderAsync(SelectedPackage.Id);
|
|
|
|
|
|
StatusMessage = $"订单创建成功,订单号: {CurrentOrder?.Id},请支付 ¥{SelectedPackage.Price}";
|
|
|
|
|
|
_logger.LogInfo($"订单创建成功,订单ID: {CurrentOrder?.Id}");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError("创建订单失败", ex);
|
|
|
|
|
|
StatusMessage = $"创建订单失败: {ex.Message}";
|
|
|
|
|
|
MessageBox.Show($"创建订单失败\n\n{ex.Message}", "错误",
|
|
|
|
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private async Task SimulatePaymentAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (CurrentOrder == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("请先创建订单", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInfo($"模拟支付,订单ID: {CurrentOrder.Id}");
|
2026-02-25 18:30:24 +08:00
|
|
|
|
|
|
|
|
|
|
// 模拟支付处理延迟
|
|
|
|
|
|
StatusMessage = "正在处理支付...";
|
|
|
|
|
|
await Task.Delay(1500);
|
|
|
|
|
|
|
|
|
|
|
|
// 确认支付
|
2026-02-25 15:43:47 +08:00
|
|
|
|
CurrentOrder = await _apiService.ConfirmPaymentAsync(CurrentOrder.Id);
|
|
|
|
|
|
StatusMessage = "支付成功!设备门已打开,请将宠物放入";
|
|
|
|
|
|
IsDoorOpen = true;
|
|
|
|
|
|
_logger.LogInfo("支付成功,门已打开");
|
2026-02-25 18:30:24 +08:00
|
|
|
|
|
|
|
|
|
|
// 显示支付成功提示
|
|
|
|
|
|
MessageBox.Show("支付成功!\n\n设备门已自动打开\n请将宠物放入设备后关闭门开始洗护",
|
|
|
|
|
|
"支付成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
|
|
|
|
|
|
|
|
|
// 返回待机界面,显示关门按钮
|
|
|
|
|
|
CurrentView = "Idle";
|
|
|
|
|
|
ViewChanged?.Invoke("Idle");
|
2026-02-25 15:43:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError("支付失败", ex);
|
|
|
|
|
|
StatusMessage = $"支付失败: {ex.Message}";
|
|
|
|
|
|
MessageBox.Show($"支付失败\n\n{ex.Message}", "错误",
|
|
|
|
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private async Task CloseDoorAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (CurrentOrder == null || !IsDoorOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("门未打开", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInfo($"关门,订单ID: {CurrentOrder.Id}");
|
|
|
|
|
|
|
|
|
|
|
|
// 通过MQTT发送关门状态
|
|
|
|
|
|
await _mqttService.PublishAsync("device/status", new
|
|
|
|
|
|
{
|
|
|
|
|
|
status = "door_closed",
|
|
|
|
|
|
orderId = CurrentOrder.Id,
|
|
|
|
|
|
timestamp = DateTime.Now
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 更新订单状态
|
|
|
|
|
|
CurrentOrder = await _apiService.UpdateOrderStatusAsync(CurrentOrder.Id, OrderStatus.DoorClosed);
|
|
|
|
|
|
|
|
|
|
|
|
IsDoorOpen = false;
|
|
|
|
|
|
StatusMessage = "门已关闭,清洗即将开始...";
|
|
|
|
|
|
_logger.LogInfo("门已关闭,等待清洗开始");
|
2026-02-25 18:30:24 +08:00
|
|
|
|
|
|
|
|
|
|
// 切换到洗护界面
|
|
|
|
|
|
CurrentView = "Washing";
|
|
|
|
|
|
ViewChanged?.Invoke("Washing");
|
|
|
|
|
|
IsWashing = true;
|
|
|
|
|
|
CurrentStep = "第一次冲水";
|
|
|
|
|
|
WashProgress = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 开始模拟洗护流程
|
|
|
|
|
|
_ = SimulateWashingProcessAsync();
|
2026-02-25 15:43:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError("关门失败", ex);
|
|
|
|
|
|
StatusMessage = $"关门失败: {ex.Message}";
|
|
|
|
|
|
MessageBox.Show($"关门失败\n\n{ex.Message}", "错误",
|
|
|
|
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 18:30:24 +08:00
|
|
|
|
private async Task SimulateWashingProcessAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var steps = new[]
|
|
|
|
|
|
{
|
|
|
|
|
|
("第一次冲水", 120),
|
|
|
|
|
|
("沐浴露喷洒", 30),
|
|
|
|
|
|
("第二次冲水", 180),
|
|
|
|
|
|
("香波喷洒", 30),
|
|
|
|
|
|
("第三次冲水", 180),
|
|
|
|
|
|
("热风吹毛", 300),
|
|
|
|
|
|
("冷热风混合", 120)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int totalDuration = steps.Sum(s => s.Item2);
|
|
|
|
|
|
int elapsed = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (int stepIndex = 0; stepIndex < steps.Length; stepIndex++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var (stepName, duration) = steps[stepIndex];
|
|
|
|
|
|
CurrentStep = stepName;
|
|
|
|
|
|
_logger.LogInfo($"开始步骤: {stepName}");
|
|
|
|
|
|
|
|
|
|
|
|
// 更新步骤状态
|
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 标记之前的步骤为已完成
|
|
|
|
|
|
for (int i = 0; i < stepIndex; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
WashSteps[i].Status = "已完成";
|
|
|
|
|
|
WashSteps[i].IsActive = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 标记当前步骤为进行中
|
|
|
|
|
|
WashSteps[stepIndex].Status = "进行中";
|
|
|
|
|
|
WashSteps[stepIndex].IsActive = true;
|
|
|
|
|
|
|
|
|
|
|
|
// 标记后续步骤为等待中
|
|
|
|
|
|
for (int i = stepIndex + 1; i < WashSteps.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
WashSteps[i].Status = "等待中";
|
|
|
|
|
|
WashSteps[i].IsActive = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i <= duration; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!IsWashing) return; // 如果被停止,退出
|
|
|
|
|
|
|
|
|
|
|
|
elapsed++;
|
|
|
|
|
|
WashProgress = (int)((double)elapsed / totalDuration * 100);
|
|
|
|
|
|
|
|
|
|
|
|
int remaining = totalDuration - elapsed;
|
|
|
|
|
|
int minutes = remaining / 60;
|
|
|
|
|
|
int seconds = remaining % 60;
|
|
|
|
|
|
RemainingTime = $"{minutes:D2}:{seconds:D2}";
|
|
|
|
|
|
|
2026-02-26 11:30:31 +08:00
|
|
|
|
// 模拟温度变化
|
|
|
|
|
|
UpdateTemperatures(stepName, i, duration);
|
|
|
|
|
|
|
2026-02-25 18:30:24 +08:00
|
|
|
|
await Task.Delay(100); // 加速模拟,实际应为1000ms
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 标记所有步骤为已完成
|
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var step in WashSteps)
|
|
|
|
|
|
{
|
|
|
|
|
|
step.Status = "已完成";
|
|
|
|
|
|
step.IsActive = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 洗护完成
|
|
|
|
|
|
await CompleteWashingAsync();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError("洗护流程失败", ex);
|
|
|
|
|
|
StatusMessage = $"洗护流程失败: {ex.Message}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task CompleteWashingAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (CurrentOrder == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInfo($"清洗完成,订单ID: {CurrentOrder.Id}");
|
|
|
|
|
|
|
|
|
|
|
|
// 发送清洗完成状态
|
|
|
|
|
|
await _mqttService.PublishAsync("device/status", new
|
|
|
|
|
|
{
|
|
|
|
|
|
status = "completed",
|
|
|
|
|
|
orderId = CurrentOrder.Id,
|
|
|
|
|
|
timestamp = DateTime.Now
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
CurrentOrder = await _apiService.UpdateOrderStatusAsync(CurrentOrder.Id, OrderStatus.Completed);
|
|
|
|
|
|
|
|
|
|
|
|
IsWashing = false;
|
|
|
|
|
|
IsDoorOpen = true;
|
|
|
|
|
|
StatusMessage = "清洗完成!请取出宠物";
|
|
|
|
|
|
|
|
|
|
|
|
MessageBox.Show("清洗完成!\n\n感谢使用无人自动洗宠机", "完成",
|
|
|
|
|
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInfo("订单流程完成");
|
|
|
|
|
|
|
|
|
|
|
|
// 返回待机界面
|
|
|
|
|
|
CurrentOrder = null;
|
|
|
|
|
|
SelectedPackage = null;
|
|
|
|
|
|
BackToIdle();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError("完成流程失败", ex);
|
|
|
|
|
|
StatusMessage = $"完成流程失败: {ex.Message}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 15:43:47 +08:00
|
|
|
|
private void OnMqttMessageReceived(string topic, string payload)
|
|
|
|
|
|
{
|
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInfo($"收到MQTT消息 - Topic: {topic}, Payload: {payload}");
|
|
|
|
|
|
var message = JsonSerializer.Deserialize<JsonElement>(payload);
|
|
|
|
|
|
|
|
|
|
|
|
if (topic == "device/command")
|
|
|
|
|
|
{
|
|
|
|
|
|
var command = message.GetProperty("command").GetString();
|
|
|
|
|
|
|
|
|
|
|
|
if (command == "open_door")
|
|
|
|
|
|
{
|
|
|
|
|
|
IsDoorOpen = true;
|
|
|
|
|
|
StatusMessage = "设备门已打开,请将宠物放入后点击关门";
|
|
|
|
|
|
_logger.LogInfo("收到开门指令");
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (command == "start_wash")
|
|
|
|
|
|
{
|
|
|
|
|
|
IsWashing = true;
|
|
|
|
|
|
var duration = message.GetProperty("durationMinutes").GetInt32();
|
|
|
|
|
|
StatusMessage = $"清洗已开始,预计 {duration} 分钟完成";
|
|
|
|
|
|
_logger.LogInfo($"收到开始清洗指令,时长: {duration}分钟");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (topic == "device/status")
|
|
|
|
|
|
{
|
|
|
|
|
|
var status = message.GetProperty("status").GetString();
|
|
|
|
|
|
StatusMessage = $"设备状态: {status}";
|
|
|
|
|
|
_logger.LogInfo($"设备状态更新: {status}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError("处理MQTT消息失败", ex);
|
|
|
|
|
|
StatusMessage = $"处理消息失败: {ex.Message}";
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-02-26 11:30:31 +08:00
|
|
|
|
|
|
|
|
|
|
private void UpdateTemperatures(string stepName, int currentTime, int totalTime)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 根据不同步骤模拟温度变化
|
|
|
|
|
|
var random = new Random();
|
|
|
|
|
|
double progress = (double)currentTime / totalTime;
|
|
|
|
|
|
|
|
|
|
|
|
switch (stepName)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "第一次冲水":
|
|
|
|
|
|
case "第二次冲水":
|
|
|
|
|
|
case "第三次冲水":
|
|
|
|
|
|
// 冲水阶段:水温在38-42度之间波动
|
|
|
|
|
|
WaterTemperature = 40.0 + (random.NextDouble() - 0.5) * 4;
|
|
|
|
|
|
RoomTemperature = 25.0 + (random.NextDouble() - 0.5) * 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "沐浴露喷洒":
|
|
|
|
|
|
case "香波喷洒":
|
|
|
|
|
|
// 喷洒阶段:水温略低
|
|
|
|
|
|
WaterTemperature = 38.0 + (random.NextDouble() - 0.5) * 2;
|
|
|
|
|
|
RoomTemperature = 25.0 + (random.NextDouble() - 0.5) * 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "热风吹毛":
|
|
|
|
|
|
// 热风阶段:水温降低,室温升高
|
|
|
|
|
|
WaterTemperature = 35.0 - progress * 10 + (random.NextDouble() - 0.5) * 2;
|
|
|
|
|
|
RoomTemperature = 25.0 + progress * 8 + (random.NextDouble() - 0.5) * 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "冷热风混合":
|
|
|
|
|
|
// 混合风阶段:温度逐渐降低
|
|
|
|
|
|
WaterTemperature = 25.0 + (random.NextDouble() - 0.5) * 2;
|
|
|
|
|
|
RoomTemperature = 30.0 - progress * 5 + (random.NextDouble() - 0.5) * 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
// 默认温度
|
|
|
|
|
|
WaterTemperature = 40.0 + (random.NextDouble() - 0.5) * 2;
|
|
|
|
|
|
RoomTemperature = 25.0 + (random.NextDouble() - 0.5) * 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 确保温度在合理范围内
|
|
|
|
|
|
WaterTemperature = Math.Max(20, Math.Min(45, WaterTemperature));
|
|
|
|
|
|
RoomTemperature = Math.Max(20, Math.Min(35, RoomTemperature));
|
|
|
|
|
|
}
|
2026-02-25 15:43:47 +08:00
|
|
|
|
}
|
2026-02-26 11:30:31 +08:00
|
|
|
|
|