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 _materials = new(); public ObservableCollection 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> MajorCategoryOptions { get; } = new(); public ObservableCollection> MinorCategoryOptions { get; } = new(); public ObservableCollection 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 EditCommand { get; } public DelegateCommand 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(async m => await ShowEditDialogAsync(m)); DeleteCommand = new DelegateCommand(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() .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("全部", "")); foreach (var item in options) { MajorCategoryOptions.Add(item); } } private async Task LoadMinorCategoryOptionsAsync() { MinorCategoryOptions.Clear(); MinorCategoryOptions.Add(new KeyValuePair("全部", "")); 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(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() .Initialize(vm => vm.InitializeForAdd()) .GetResultAsync(); 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() .Initialize(vm => vm.InitializeForEdit(material)) .GetResultAsync(); 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().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 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 children) { Id = id; DisplayName = displayName ?? id; Code = code; IsMajor = isMajor; ParentId = parentId; Children = new ObservableCollection(children); } } }