完成编辑设备

This commit is contained in:
2025-07-29 20:02:09 +08:00
parent 61807bfc65
commit 3b5ecef895
8 changed files with 95 additions and 109 deletions

View File

@@ -1,19 +0,0 @@
using DMS.Core.Enums;
namespace DMS.Application.DTOs;
/// <summary>
/// 用于更新设备时传输数据的DTO。
/// </summary>
public class UpdateDeviceDto
{
public int Id { get; set; }
public string? Name { get; set; }
public ProtocolType? Protocol { get; set; }
public string? IpAddress { get; set; }
public int? Port { get; set; }
public int? Rack { get; set; }
public int? Slot { get; set; }
public string? OpcUaServerUrl { get; set; }
public bool? IsActive { get; set; }
}

View File

@@ -29,7 +29,7 @@ public interface IDeviceAppService
/// <summary> /// <summary>
/// 异步更新一个已存在的设备。 /// 异步更新一个已存在的设备。
/// </summary> /// </summary>
Task<int> UpdateDeviceAsync(UpdateDeviceDto deviceDto); Task<int> UpdateDeviceAsync(DeviceDto deviceDto);
/// <summary> /// <summary>
/// 异步删除一个设备。 /// 异步删除一个设备。

View File

@@ -13,25 +13,25 @@ public class MappingProfile : Profile
{ {
// Device 映射 // // Device 映射
CreateMap<UpdateDeviceDto, Device>() // CreateMap<UpdateDeviceDto, Device>()
// 1. 首先忽略那些永远不应从DTO更新的属性 // // 1. 首先忽略那些永远不应从DTO更新的属性
.ForMember(dest => dest.Id, opt => opt.Ignore()) // .ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.Description, opt => opt.Ignore()) // .ForMember(dest => dest.Description, opt => opt.Ignore())
.ForMember(dest => dest.VariableTables, opt => opt.Ignore()) // .ForMember(dest => dest.VariableTables, opt => opt.Ignore())
.ForMember(dest => dest.CpuType, opt => opt.Ignore()) // .ForMember(dest => dest.CpuType, opt => opt.Ignore())
.ForMember(dest => dest.IsRunning, opt => opt.Ignore()) // .ForMember(dest => dest.IsRunning, opt => opt.Ignore())
.ForMember(dest => dest.DeviceType, opt => opt.Ignore()) // .ForMember(dest => dest.DeviceType, opt => opt.Ignore())
//
// 2. 然后,为每个可空属性单独设置条件 // // 2. 然后,为每个可空属性单独设置条件
.ForMember(dest => dest.Name, opt => opt.Condition(src => src.Name != null)) // .ForMember(dest => dest.Name, opt => opt.Condition(src => src.Name != null))
.ForMember(dest => dest.Protocol, opt => opt.Condition(src => src.Protocol.HasValue)) // .ForMember(dest => dest.Protocol, opt => opt.Condition(src => src.Protocol.HasValue))
.ForMember(dest => dest.IpAddress, opt => opt.Condition(src => src.IpAddress != null)) // .ForMember(dest => dest.IpAddress, opt => opt.Condition(src => src.IpAddress != null))
.ForMember(dest => dest.Port, opt => opt.Condition(src => src.Port.HasValue)) // .ForMember(dest => dest.Port, opt => opt.Condition(src => src.Port.HasValue))
.ForMember(dest => dest.Rack, opt => opt.Condition(src => src.Rack.HasValue)) // .ForMember(dest => dest.Rack, opt => opt.Condition(src => src.Rack.HasValue))
.ForMember(dest => dest.Slot, opt => opt.Condition(src => src.Slot.HasValue)) // .ForMember(dest => dest.Slot, opt => opt.Condition(src => src.Slot.HasValue))
.ForMember(dest => dest.OpcUaServerUrl, opt => opt.Condition(src => src.OpcUaServerUrl != null)) // .ForMember(dest => dest.OpcUaServerUrl, opt => opt.Condition(src => src.OpcUaServerUrl != null))
.ForMember(dest => dest.IsActive, opt => opt.Condition(src => src.IsActive.HasValue)); // .ForMember(dest => dest.IsActive, opt => opt.Condition(src => src.IsActive.HasValue));
CreateMap<Device, DeviceDto>() CreateMap<Device, DeviceDto>()
.ReverseMap(); .ReverseMap();

View File

@@ -135,7 +135,7 @@ public class DeviceAppService : IDeviceAppService
/// <param name="deviceDto">要更新的设备数据传输对象。</param> /// <param name="deviceDto">要更新的设备数据传输对象。</param>
/// <returns>受影响的行数。</returns> /// <returns>受影响的行数。</returns>
/// <exception cref="ApplicationException">如果找不到设备。</exception> /// <exception cref="ApplicationException">如果找不到设备。</exception>
public async Task<int> UpdateDeviceAsync(UpdateDeviceDto deviceDto) public async Task<int> UpdateDeviceAsync(DeviceDto deviceDto)
{ {
await _repoManager.BeginTranAsync(); await _repoManager.BeginTranAsync();
var device = await _repoManager.Devices.GetByIdAsync(deviceDto.Id); var device = await _repoManager.Devices.GetByIdAsync(deviceDto.Id);
@@ -146,6 +146,12 @@ public class DeviceAppService : IDeviceAppService
_mapper.Map(deviceDto, device); _mapper.Map(deviceDto, device);
int res=await _repoManager.Devices.UpdateAsync(device); int res=await _repoManager.Devices.UpdateAsync(device);
var menu=await _repoManager.Menus.GetMenuByTargetIdAsync(MenuType.DeviceMenu, deviceDto.Id);
if (menu != null)
{
menu.Header = device.Name;
await _repoManager.Menus.UpdateAsync(menu);
}
await _repoManager.CommitAsync(); await _repoManager.CommitAsync();
return res; return res;
} }

View File

@@ -52,16 +52,16 @@ public class DeviceAppServiceTest : BaseServiceTest // 继承基类
[Fact] [Fact]
public async Task UpdateDeviceAsyncTest() public async Task UpdateDeviceAsyncTest()
{ {
UpdateDeviceDto dto = new UpdateDeviceDto() // UpdateDeviceDto dto = new UpdateDeviceDto()
{ // {
Id = 5, // Id = 5,
Name = "lalala", // Name = "lalala",
IsActive = true, // IsActive = true,
Rack = 0, // Rack = 0,
Slot = 0 // Slot = 0
//
}; // };
var res = await _deviceService.UpdateDeviceAsync(dto); // var res = await _deviceService.UpdateDeviceAsync(dto);
Assert.NotEqual(res,0); // Assert.NotEqual(res,0);
} }
} }

View File

@@ -60,18 +60,6 @@ public partial class DevicesViewModel : ViewModelBase, INavigatable
DataServices.OnDeviceListChanged += (devices) => { }; DataServices.OnDeviceListChanged += (devices) => { };
} }
// public override void OnLoaded()
// {
// if (_dataServices.Devices!=null && _dataServices.Devices.Count>0)
// {
// Devices=new ObservableCollection<Device>(_dataServices.Devices);
// foreach (var device in Devices)
// {
// device.OnDeviceIsActiveChanged += HandleDeviceIsActiveChanged;
//
// }
// }
// }
public override Task<bool> OnExitAsync() public override Task<bool> OnExitAsync()
{ {
@@ -86,19 +74,6 @@ public partial class DevicesViewModel : ViewModelBase, INavigatable
return Task.FromResult(true); return Task.FromResult(true);
} }
private async void HandleDeviceIsActiveChanged(Device device, bool isActive)
{
// try
// {
// await _deviceRepository.UpdateAsync(device);
// NotificationHelper.ShowSuccess($"设备 {device.Name} 的激活状态已更新。");
// }
// catch (Exception ex)
// {
// NotificationHelper.ShowError($"更新设备 {device.Name} 激活状态失败: {ex.Message}", ex);
// }
}
/// <summary> /// <summary>
/// 添加设备命令。 /// 添加设备命令。
/// </summary> /// </summary>
@@ -107,8 +82,7 @@ public partial class DevicesViewModel : ViewModelBase, INavigatable
{ {
try try
{ {
DeviceItemViewModel deviceItemViewModel = new DeviceItemViewModel(); DeviceDialogViewModel deviceDialogViewModel = new DeviceDialogViewModel()
DeviceDialogViewModel deviceDialogViewModel = new DeviceDialogViewModel(deviceItemViewModel)
{ {
PrimaryButContent = "添加设备" PrimaryButContent = "添加设备"
}; };
@@ -208,31 +182,42 @@ public partial class DevicesViewModel : ViewModelBase, INavigatable
[RelayCommand] [RelayCommand]
public async void EditDevice() public async void EditDevice()
{ {
// try try
// { {
// if (SelectedDevice == null) if (SelectedDevice == null)
// { {
// NotificationHelper.ShowError("你没有选择任何设备,请选择设备后再点击编辑设备"); NotificationHelper.ShowError("你没有选择任何设备,请选择设备后再点击编辑设备");
// return; return;
// } }
//
// var editDievce = await _dialogService.ShowEditDeviceDialog(SelectedDevice); DeviceDialogViewModel deviceDialogViewModel = new DeviceDialogViewModel(SelectedDevice)
// if (editDievce != null) {
// { PrimaryButContent = "编辑设备"
// // 更新菜单 };
// var res = await _deviceRepository.UpdateAsync(editDievce); // 1. 显示设备对话框
// var menu = DataServicesHelper.FindMenusForDevice(editDievce, _dataServices.MenuTrees); DeviceItemViewModel device = await _dialogService.ShowDialogAsync(deviceDialogViewModel);
// if (menu != null) // 如果用户取消或对话框未返回设备,则直接返回
// await _menuRepository.UpdateAsync(menu); if (device == null)
// {
// MessageHelper.SendLoadMessage(LoadTypes.Menu); return;
// MessageHelper.SendLoadMessage(LoadTypes.Devices); }
// }
// } int res = await _deviceAppService.UpdateDeviceAsync(_mapper.Map<DeviceDto>(device));
// catch (Exception e) if (res > 0)
// { {
// NotificationHelper.ShowError($"编辑设备的过程中发生错误:{e.Message}", e); var menu = DataServices.Menus.FirstOrDefault(m =>
// } m.MenuType == MenuType.DeviceMenu &&
m.TargetId == device.Id);
if (menu!=null)
{
menu.Header=device.Name;
}
}
}
catch (Exception e)
{
NotificationHelper.ShowError($"编辑设备的过程中发生错误:{e.Message}", e);
}
} }
[RelayCommand] [RelayCommand]

View File

@@ -7,15 +7,25 @@ namespace DMS.WPF.ViewModels.Dialogs;
public partial class DeviceDialogViewModel : DialogViewModelBase<DeviceItemViewModel> public partial class DeviceDialogViewModel : DialogViewModelBase<DeviceItemViewModel>
{ {
[ObservableProperty]
private bool _isAddMode;
[ObservableProperty] [ObservableProperty]
private DeviceItemViewModel _device; private DeviceItemViewModel _device;
public DeviceDialogViewModel(DeviceItemViewModel device) public DeviceDialogViewModel(DeviceItemViewModel device=null)
{
if (device==null)
{
_device = new DeviceItemViewModel();
IsAddMode=true;
}
else
{ {
_device=device; _device=device;
}
} }
[RelayCommand] [RelayCommand]

View File

@@ -65,7 +65,9 @@
<TextBlock Text="设备类型" <TextBlock Text="设备类型"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Style="{StaticResource TextBlockSubTitle}" /> Style="{StaticResource TextBlockSubTitle}" />
<ComboBox SelectedItem="{Binding Device.DeviceType}" <ComboBox
IsEnabled="{Binding IsAddMode}"
SelectedItem="{Binding Device.DeviceType}"
ItemsSource="{Binding Source={StaticResource deviceType} }"> ItemsSource="{Binding Source={StaticResource deviceType} }">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>
@@ -102,7 +104,9 @@
<TextBlock Text="设备通信协议" <TextBlock Text="设备通信协议"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Style="{StaticResource TextBlockSubTitle}" /> Style="{StaticResource TextBlockSubTitle}" />
<ComboBox x:Name="ProtocolComboBox" SelectedItem="{Binding Device.Protocol}" <ComboBox x:Name="ProtocolComboBox"
IsEnabled="{Binding IsAddMode}"
SelectedItem="{Binding Device.Protocol}"
ItemsSource="{Binding Source={StaticResource protocolType} }"> ItemsSource="{Binding Source={StaticResource protocolType} }">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>