diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 54e6365..f05baa9 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -16,7 +16,8 @@ "Bash(sed -i '' '/Console.WriteLine/d' Views/MainWindow.axaml.cs)", "Bash(sed -i '' '/System.Console.WriteLine/d' ViewModels/Device/DeviceHostViewModel.cs)", "Bash(sed -i '' '/System.Console.WriteLine/d' Views/Device/DeviceHostListView.axaml.cs)", - "Bash(git status *)" + "Bash(git status *)", + "Bash(dotnet /Users/wenxiansheng/.nuget/packages/avalonia/11.1.5/lib/netstandard2.0/Avalonia.Base.dll type list)" ] } } diff --git a/Sln.Wcs.UI/ViewModels/Device/DeviceInfoViewModel.cs b/Sln.Wcs.UI/ViewModels/Device/DeviceInfoViewModel.cs index 8fa1b03..93e965b 100644 --- a/Sln.Wcs.UI/ViewModels/Device/DeviceInfoViewModel.cs +++ b/Sln.Wcs.UI/ViewModels/Device/DeviceInfoViewModel.cs @@ -1,15 +1,32 @@ using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq.Expressions; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; using Sln.Wcs.Model.Domain; using Sln.Wcs.Repository.service; using Sln.Wcs.UI.ViewModels.Base; +using Sln.Wcs.UI.Views.Base; namespace Sln.Wcs.UI.ViewModels.Device; -public class DeviceInfoViewModel : CrudPageViewModel +public partial class DeviceInfoViewModel : CrudPageViewModel { - public DeviceInfoViewModel(IBaseDeviceInfoService service) : base(service) + private readonly IBaseDeviceParamService _paramService; + private BaseDeviceInfo? _currentDevice; + + [ObservableProperty] + private bool _isPanelOpen; + + [ObservableProperty] + private ObservableCollection _deviceParams = new(); + + [ObservableProperty] + private string _slidePanelTitle = string.Empty; + + public DeviceInfoViewModel(IBaseDeviceInfoService service, IBaseDeviceParamService paramService) : base(service) { + _paramService = paramService; PageTitle = "设备信息管理"; } @@ -30,4 +47,77 @@ public class DeviceInfoViewModel : CrudPageViewModel => x => x.deviceCode.Contains(search) || (x.deviceName != null && x.deviceName.Contains(search)); public override Avalonia.Controls.Control CreateView() => new Sln.Wcs.UI.Views.Device.DeviceInfoListView(); + + public void LoadParamsData(BaseDeviceInfo device) + { + _currentDevice = device; + LoadParams(); + SlidePanelTitle = $"设备参数 - {device.deviceCode}"; + } + + [RelayCommand] + public void ClosePanel() + { + IsPanelOpen = false; + } + + [RelayCommand] + private async System.Threading.Tasks.Task AddParam() + { + if (_currentDevice is null) return; + var entity = new BaseDeviceParam { deviceCode = _currentDevice.deviceCode }; + var editor = new EntityEditWindow(); + var result = await editor.ShowDialog(entity, ParamFieldConfigs, false, GetMainWindow()); + if (result) + { + _paramService.Insert(entity); + LoadParams(); + } + } + + public async System.Threading.Tasks.Task EditParamAsync(BaseDeviceParam param) + { + var editor = new EntityEditWindow(); + var result = await editor.ShowDialog(param, ParamFieldConfigs, true, GetMainWindow()); + if (result) + { + _paramService.Update(param); + LoadParams(); + } + } + + public void DeleteParam(BaseDeviceParam param) + { + _paramService.DeleteById(param.objId); + LoadParams(); + } + + private void LoadParams() + { + if (_currentDevice is null) return; + var list = _paramService.Query(x => x.deviceCode == _currentDevice.deviceCode); + DeviceParams = new ObservableCollection(list); + } + + public List ParamFieldConfigs => new() + { + new() { PropertyName = "paramCode", DisplayName = "参数编号", IsRequired = true }, + new() { PropertyName = "deviceCode", DisplayName = "设备编号", IsRequired = true, IsReadOnly = true }, + new() { PropertyName = "paramName", DisplayName = "参数名称", IsRequired = true }, + new() { PropertyName = "paramAddress", DisplayName = "参数地址", IsRequired = true }, + new() { PropertyName = "paramType", DisplayName = "参数类型" }, + new() { PropertyName = "paramValue", DisplayName = "参数值", FieldType = FieldType.Number }, + new() { PropertyName = "operationType", DisplayName = "操作类型" }, + new() { PropertyName = "operationFrequency", DisplayName = "操作频率(ms)" }, + new() { PropertyName = "isFlag", DisplayName = "启用", FieldType = FieldType.CheckBox }, + new() { PropertyName = "remark", DisplayName = "备注" }, + }; + + private Avalonia.Controls.Window GetMainWindow() + { + return (Avalonia.Controls.Window)Avalonia.Application.Current! + .ApplicationLifetime!.GetType() + .GetProperty("MainWindow")! + .GetValue(Avalonia.Application.Current.ApplicationLifetime)!; + } } diff --git a/Sln.Wcs.UI/ViewModels/Path/PathInfoViewModel.cs b/Sln.Wcs.UI/ViewModels/Path/PathInfoViewModel.cs index 9325ef3..ff0fd69 100644 --- a/Sln.Wcs.UI/ViewModels/Path/PathInfoViewModel.cs +++ b/Sln.Wcs.UI/ViewModels/Path/PathInfoViewModel.cs @@ -1,15 +1,32 @@ using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq.Expressions; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; using Sln.Wcs.Model.Domain; using Sln.Wcs.Repository.service; using Sln.Wcs.UI.ViewModels.Base; +using Sln.Wcs.UI.Views.Base; namespace Sln.Wcs.UI.ViewModels.Path; -public class PathInfoViewModel : CrudPageViewModel +public partial class PathInfoViewModel : CrudPageViewModel { - public PathInfoViewModel(IBasePathInfoService service) : base(service) + private readonly IBasePathDetailsService _detailService; + private BasePathInfo? _currentPath; + + [ObservableProperty] + private bool _isPanelOpen; + + [ObservableProperty] + private ObservableCollection _detailItems = new(); + + [ObservableProperty] + private string _slidePanelTitle = string.Empty; + + public PathInfoViewModel(IBasePathInfoService service, IBasePathDetailsService detailService) : base(service) { + _detailService = detailService; PageTitle = "路径信息管理"; } @@ -30,4 +47,74 @@ public class PathInfoViewModel : CrudPageViewModel || (x.pathName != null && x.pathName.Contains(search)); public override Avalonia.Controls.Control CreateView() => new Sln.Wcs.UI.Views.Path.PathInfoListView(); + + public void LoadDetailsData(BasePathInfo path) + { + _currentPath = path; + LoadDetails(); + SlidePanelTitle = $"路径明细 - {path.pathCode}"; + } + + [RelayCommand] + public void ClosePanel() + { + IsPanelOpen = false; + } + + [RelayCommand] + private async System.Threading.Tasks.Task AddDetail() + { + if (_currentPath is null) return; + var entity = new BasePathDetails { pathCode = _currentPath.pathCode }; + var editor = new EntityEditWindow(); + var result = await editor.ShowDialog(entity, DetailFieldConfigs, false, GetMainWindow()); + if (result) + { + _detailService.Insert(entity); + LoadDetails(); + } + } + + public async System.Threading.Tasks.Task EditDetailAsync(BasePathDetails detail) + { + var editor = new EntityEditWindow(); + var result = await editor.ShowDialog(detail, DetailFieldConfigs, true, GetMainWindow()); + if (result) + { + _detailService.Update(detail); + LoadDetails(); + } + } + + public void DeleteDetail(BasePathDetails detail) + { + _detailService.DeleteById(detail.objId); + LoadDetails(); + } + + private void LoadDetails() + { + if (_currentPath is null) return; + var list = _detailService.Query(x => x.pathCode == _currentPath.pathCode); + DetailItems = new ObservableCollection(list); + } + + public List DetailFieldConfigs => new() + { + new() { PropertyName = "pathCode", DisplayName = "路径编号", IsRequired = true, IsReadOnly = true }, + new() { PropertyName = "pathName", DisplayName = "路径名称" }, + new() { PropertyName = "startPoint", DisplayName = "起点", IsRequired = true }, + new() { PropertyName = "endPoint", DisplayName = "终点", IsRequired = true }, + new() { PropertyName = "deviceType", DisplayName = "设备类型", FieldType = FieldType.Number }, + new() { PropertyName = "isFlag", DisplayName = "启用", FieldType = FieldType.CheckBox }, + new() { PropertyName = "remark", DisplayName = "备注" }, + }; + + private Avalonia.Controls.Window GetMainWindow() + { + return (Avalonia.Controls.Window)Avalonia.Application.Current! + .ApplicationLifetime!.GetType() + .GetProperty("MainWindow")! + .GetValue(Avalonia.Application.Current.ApplicationLifetime)!; + } } diff --git a/Sln.Wcs.UI/ViewModels/Task/TaskQueueViewModel.cs b/Sln.Wcs.UI/ViewModels/Task/TaskQueueViewModel.cs index 685b8af..5c036ad 100644 --- a/Sln.Wcs.UI/ViewModels/Task/TaskQueueViewModel.cs +++ b/Sln.Wcs.UI/ViewModels/Task/TaskQueueViewModel.cs @@ -1,15 +1,32 @@ using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq.Expressions; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; using Sln.Wcs.Model.Domain; using Sln.Wcs.Repository.service; using Sln.Wcs.UI.ViewModels.Base; +using Sln.Wcs.UI.Views.Base; namespace Sln.Wcs.UI.ViewModels.Task; -public class TaskQueueViewModel : CrudPageViewModel +public partial class TaskQueueViewModel : CrudPageViewModel { - public TaskQueueViewModel(ILiveTaskQueueService service) : base(service) + private readonly ILiveTaskDetailService _detailService; + private LiveTaskQueue? _currentTask; + + [ObservableProperty] + private bool _isPanelOpen; + + [ObservableProperty] + private ObservableCollection _detailItems = new(); + + [ObservableProperty] + private string _slidePanelTitle = string.Empty; + + public TaskQueueViewModel(ILiveTaskQueueService service, ILiveTaskDetailService detailService) : base(service) { + _detailService = detailService; PageTitle = "任务队列管理"; } @@ -36,4 +53,77 @@ public class TaskQueueViewModel : CrudPageViewModel || (x.materialCode != null && x.materialCode.Contains(search)); public override Avalonia.Controls.Control CreateView() => new Sln.Wcs.UI.Views.Task.TaskQueueListView(); + + public void LoadDetailsData(LiveTaskQueue task) + { + _currentTask = task; + LoadDetails(); + SlidePanelTitle = $"任务明细 - {task.taskCode}"; + } + + [RelayCommand] + public void ClosePanel() + { + IsPanelOpen = false; + } + + [RelayCommand] + private async System.Threading.Tasks.Task AddDetail() + { + if (_currentTask is null) return; + var entity = new LiveTaskDetail { taskCode = _currentTask.taskCode }; + var editor = new EntityEditWindow(); + var result = await editor.ShowDialog(entity, DetailFieldConfigs, false, GetMainWindow()); + if (result) + { + _detailService.Insert(entity); + LoadDetails(); + } + } + + public async System.Threading.Tasks.Task EditDetailAsync(LiveTaskDetail detail) + { + var editor = new EntityEditWindow(); + var result = await editor.ShowDialog(detail, DetailFieldConfigs, true, GetMainWindow()); + if (result) + { + _detailService.Update(detail); + LoadDetails(); + } + } + + public void DeleteDetail(LiveTaskDetail detail) + { + _detailService.DeleteById(detail.objId); + LoadDetails(); + } + + private void LoadDetails() + { + if (_currentTask is null) return; + var list = _detailService.Query(x => x.taskCode == _currentTask.taskCode); + DetailItems = new ObservableCollection(list); + } + + public List DetailFieldConfigs => new() + { + new() { PropertyName = "taskCode", DisplayName = "任务编号", IsRequired = true, IsReadOnly = true }, + new() { PropertyName = "pathCode", DisplayName = "路径编号" }, + new() { PropertyName = "materialCode", DisplayName = "物料编号" }, + new() { PropertyName = "startPoint", DisplayName = "起始位置" }, + new() { PropertyName = "endPoint", DisplayName = "结束位置" }, + new() { PropertyName = "deviceType", DisplayName = "设备类型", FieldType = FieldType.Number }, + new() { PropertyName = "isValidate", DisplayName = "校验物料", FieldType = FieldType.CheckBox }, + new() { PropertyName = "taskStatus", DisplayName = "任务状态", FieldType = FieldType.Number }, + new() { PropertyName = "isFlag", DisplayName = "启用", FieldType = FieldType.CheckBox }, + new() { PropertyName = "remark", DisplayName = "备注" }, + }; + + private Avalonia.Controls.Window GetMainWindow() + { + return (Avalonia.Controls.Window)Avalonia.Application.Current! + .ApplicationLifetime!.GetType() + .GetProperty("MainWindow")! + .GetValue(Avalonia.Application.Current.ApplicationLifetime)!; + } } diff --git a/Sln.Wcs.UI/Views/Device/DeviceInfoListView.axaml b/Sln.Wcs.UI/Views/Device/DeviceInfoListView.axaml index cdc0745..793fabb 100644 --- a/Sln.Wcs.UI/Views/Device/DeviceInfoListView.axaml +++ b/Sln.Wcs.UI/Views/Device/DeviceInfoListView.axaml @@ -1,14 +1,14 @@ - +