Files
qhmes/yy-admin-master/YY.Admin/ViewModels/MixerMaterial/MixerMaterialListViewModel.cs

382 lines
13 KiB
C#

using HandyControl.Controls;
using HandyControl.Tools.Extension;
using Prism.Events;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using YY.Admin.Core;
using YY.Admin.Core.Entity;
using YY.Admin.Core.Events;
using YY.Admin.Core.Helper;
using YY.Admin.Core.Services;
using YY.Admin.Views.MixerMaterial;
namespace YY.Admin.ViewModels.MixerMaterial;
public class MixerMaterialListViewModel : BaseViewModel
{
private readonly IMixerMaterialService _mixerMaterialService;
private SubscriptionToken? _materialChangedToken;
private ObservableCollection<MesMixerMaterial> _materials = new();
public ObservableCollection<MesMixerMaterial> Materials
{
get => _materials;
set => SetProperty(ref _materials, value);
}
private long _total;
public long Total { get => _total; set => SetProperty(ref _total, value); }
private int _pageNo = 1;
public int PageNo { get => _pageNo; set => SetProperty(ref _pageNo, value); }
private int _pageSize = 20;
public int PageSize { get => _pageSize; set => SetProperty(ref _pageSize, value); }
private string? _filterMaterialCode;
public string? FilterMaterialCode { get => _filterMaterialCode; set => SetProperty(ref _filterMaterialCode, value); }
private string? _filterMaterialName;
public string? FilterMaterialName { get => _filterMaterialName; set => SetProperty(ref _filterMaterialName, value); }
private string? _filterErpCode;
public string? FilterErpCode { get => _filterErpCode; set => SetProperty(ref _filterErpCode, value); }
private string? _filterMajorCategoryId;
public string? FilterMajorCategoryId
{
get => _filterMajorCategoryId;
set
{
if (SetProperty(ref _filterMajorCategoryId, value))
{
_ = OnMajorCategoryChangedAsync();
}
}
}
private string? _filterMinorCategoryId;
public string? FilterMinorCategoryId { get => _filterMinorCategoryId; set => SetProperty(ref _filterMinorCategoryId, value); }
public ObservableCollection<KeyValuePair<string, string>> MajorCategoryOptions { get; } = new();
public ObservableCollection<KeyValuePair<string, string>> MinorCategoryOptions { get; } = new();
public ObservableCollection<CategoryFilterNode> TreeNodes { get; } = new();
private CategoryFilterNode? _selectedTreeNode;
public CategoryFilterNode? SelectedTreeNode
{
get => _selectedTreeNode;
set => SetProperty(ref _selectedTreeNode, value);
}
private bool _isTreeAllExpanded = true;
public bool IsTreeAllExpanded
{
get => _isTreeAllExpanded;
set
{
if (SetProperty(ref _isTreeAllExpanded, value))
RaisePropertyChanged(nameof(ToggleExpandButtonText));
}
}
public string ToggleExpandButtonText => _isTreeAllExpanded ? "折叠全部" : "展开全部";
private bool _isSyncing;
public bool IsSyncing { get => _isSyncing; set => SetProperty(ref _isSyncing, value); }
public DelegateCommand SearchCommand { get; }
public DelegateCommand ResetCommand { get; }
public DelegateCommand AddCommand { get; }
public DelegateCommand PullAllCommand { get; }
public DelegateCommand<MesMixerMaterial> EditCommand { get; }
public DelegateCommand<MesMixerMaterial> DeleteCommand { get; }
public DelegateCommand PrevPageCommand { get; }
public DelegateCommand NextPageCommand { get; }
public DelegateCommand ToggleExpandCommand { get; }
public MixerMaterialListViewModel(
IMixerMaterialService mixerMaterialService,
IContainerExtension container,
IRegionManager regionManager) : base(container, regionManager)
{
_mixerMaterialService = mixerMaterialService;
SearchCommand = new DelegateCommand(async () => { PageNo = 1; await LoadAsync(); });
ResetCommand = new DelegateCommand(async () =>
{
FilterMaterialCode = null;
FilterMaterialName = null;
FilterErpCode = null;
_filterMajorCategoryId = null;
RaisePropertyChanged(nameof(FilterMajorCategoryId));
FilterMinorCategoryId = null;
SelectedTreeNode = null;
await LoadMinorCategoryOptionsAsync();
PageNo = 1;
await LoadAsync();
});
AddCommand = new DelegateCommand(async () => await ShowAddDialogAsync());
EditCommand = new DelegateCommand<MesMixerMaterial>(async m => await ShowEditDialogAsync(m));
DeleteCommand = new DelegateCommand<MesMixerMaterial>(async m => await DeleteAsync(m));
PrevPageCommand = new DelegateCommand(async () => { if (PageNo > 1) { PageNo--; await LoadAsync(); } });
NextPageCommand = new DelegateCommand(async () => { if ((long)PageNo * PageSize < Total) { PageNo++; await LoadAsync(); } });
ToggleExpandCommand = new DelegateCommand(ToggleExpand);
PullAllCommand = new DelegateCommand(async () =>
{
if (IsSyncing) return;
IsSyncing = true;
try
{
await _mixerMaterialService.SyncFromRemoteAsync();
await LoadAsync();
Growl.Success("全量拉取完成!");
}
catch (Exception ex)
{
Growl.Error($"全量拉取失败:{ex.Message}");
}
finally
{
IsSyncing = false;
}
});
_materialChangedToken = _eventAggregator
.GetEvent<MixerMaterialChangedEvent>()
.Subscribe(async _ => await LoadAsync(), ThreadOption.UIThread);
_ = InitializeAsync();
}
private async Task InitializeAsync()
{
try
{
await LoadCategoryTreeAsync();
await LoadMajorCategoryOptionsAsync();
await LoadMinorCategoryOptionsAsync();
await UIHelper.WaitForRenderAsync();
await LoadAsync();
}
catch (Exception ex)
{
Debug.WriteLine($"密炼物料列表初始化失败: {ex.Message}");
}
}
private async Task LoadCategoryTreeAsync()
{
try
{
var tree = await _mixerMaterialService.GetMaterialCategoryTreeAsync();
TreeNodes.Clear();
var root = new CategoryFilterNode("", "全部", null, false, null, []) { IsExpanded = true };
foreach (var major in tree)
{
var majorNode = new CategoryFilterNode(major.Id, major.Name ?? major.Code ?? major.Id, major.Code, true, null, []);
foreach (var minor in major.Children)
{
majorNode.Children.Add(new CategoryFilterNode(minor.Id, minor.Name ?? minor.Code ?? minor.Id, minor.Code, false, major.Id, []));
}
root.Children.Add(majorNode);
}
TreeNodes.Add(root);
IsTreeAllExpanded = false;
}
catch (Exception ex)
{
Debug.WriteLine($"加载物料分类树失败: {ex.Message}");
}
}
private void ToggleExpand()
{
var expand = !_isTreeAllExpanded;
foreach (var root in TreeNodes)
{
root.IsExpanded = true; // 根节点始终展开
foreach (var major in root.Children)
major.IsExpanded = expand;
}
IsTreeAllExpanded = expand;
}
public async Task OnTreeNodeSelectedAsync(CategoryFilterNode? node)
{
SelectedTreeNode = node;
if (node == null || node.Id == "")
{
_filterMajorCategoryId = null;
RaisePropertyChanged(nameof(FilterMajorCategoryId));
FilterMinorCategoryId = null;
}
else if (node.IsMajor)
{
_filterMajorCategoryId = node.Id;
RaisePropertyChanged(nameof(FilterMajorCategoryId));
FilterMinorCategoryId = null;
}
else
{
_filterMajorCategoryId = node.ParentId;
RaisePropertyChanged(nameof(FilterMajorCategoryId));
FilterMinorCategoryId = node.Id;
}
await LoadMinorCategoryOptionsAsync();
PageNo = 1;
await LoadAsync();
}
private async Task LoadMajorCategoryOptionsAsync()
{
MajorCategoryOptions.Clear();
var options = await _mixerMaterialService.GetMajorCategoryOptionsAsync();
MajorCategoryOptions.Add(new KeyValuePair<string, string>("全部", ""));
foreach (var item in options)
{
MajorCategoryOptions.Add(item);
}
}
private async Task LoadMinorCategoryOptionsAsync()
{
MinorCategoryOptions.Clear();
MinorCategoryOptions.Add(new KeyValuePair<string, string>("全部", ""));
if (string.IsNullOrWhiteSpace(_filterMajorCategoryId))
{
return;
}
var options = await _mixerMaterialService.GetMinorCategoryOptionsAsync(_filterMajorCategoryId!);
foreach (var item in options)
{
MinorCategoryOptions.Add(item);
}
}
private async Task OnMajorCategoryChangedAsync()
{
FilterMinorCategoryId = null;
await LoadMinorCategoryOptionsAsync();
}
public async Task LoadAsync()
{
try
{
IsLoading = true;
var result = await _mixerMaterialService.PageAsync(
PageNo, PageSize, FilterMaterialCode, FilterMaterialName, FilterErpCode, _filterMajorCategoryId, FilterMinorCategoryId);
Materials = new ObservableCollection<MesMixerMaterial>(result.Records);
Total = result.Total;
}
catch (Exception ex)
{
Growl.Error($"加载密炼物料列表失败:{ex.Message}");
}
finally
{
IsLoading = false;
}
}
private async Task ShowAddDialogAsync()
{
try
{
var result = await HandyControl.Controls.Dialog.Show<MixerMaterialEditDialogView>()
.Initialize<MixerMaterialEditDialogViewModel>(vm => vm.InitializeForAdd())
.GetResultAsync<bool>();
if (result) await LoadAsync();
}
catch (Exception ex)
{
Growl.Error($"打开新增对话框失败:{ex.Message}");
}
}
private async Task ShowEditDialogAsync(MesMixerMaterial material)
{
if (material == null) return;
try
{
var result = await HandyControl.Controls.Dialog.Show<MixerMaterialEditDialogView>()
.Initialize<MixerMaterialEditDialogViewModel>(vm => vm.InitializeForEdit(material))
.GetResultAsync<bool>();
if (result) await LoadAsync();
}
catch (Exception ex)
{
Growl.Error($"打开编辑对话框失败:{ex.Message}");
}
}
private async Task DeleteAsync(MesMixerMaterial material)
{
if (material?.Id == null) return;
var confirm = System.Windows.MessageBox.Show($"确定删除物料 {material.MaterialName}?此操作不可恢复!", "确认删除",
MessageBoxButton.OKCancel, MessageBoxImage.Question);
if (confirm != System.Windows.MessageBoxResult.OK) return;
var ok = await _mixerMaterialService.DeleteAsync(material.Id);
if (ok)
{
Growl.Success("删除成功!");
await LoadAsync();
}
else
{
Growl.Error("删除失败!");
}
}
protected override void CleanUp()
{
base.CleanUp();
if (_materialChangedToken != null)
{
_eventAggregator.GetEvent<MixerMaterialChangedEvent>().Unsubscribe(_materialChangedToken);
_materialChangedToken = null;
}
}
public class CategoryFilterNode : System.ComponentModel.INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged;
public string Id { get; }
public string DisplayName { get; }
public string? Code { get; }
public bool IsMajor { get; }
public string? ParentId { get; }
public ObservableCollection<CategoryFilterNode> Children { get; }
private bool _isExpanded;
public bool IsExpanded
{
get => _isExpanded;
set
{
if (_isExpanded != value)
{
_isExpanded = value;
PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(nameof(IsExpanded)));
}
}
}
public CategoryFilterNode(string id, string? displayName, string? code, bool isMajor, string? parentId, List<CategoryFilterNode> children)
{
Id = id;
DisplayName = displayName ?? id;
Code = code;
IsMajor = isMajor;
ParentId = parentId;
Children = new ObservableCollection<CategoryFilterNode>(children);
}
}
}