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.Services.Service; using YY.Admin.Views.Print; using YY.Admin.Views.RawMaterialCard; namespace YY.Admin.ViewModels.RawMaterialCard; public class RawMaterialCardListViewModel : BaseViewModel { private readonly IRawMaterialCardService _cardService; private readonly IJeecgDictSyncService _dictSyncService; private readonly IPrintDotService _printDotService; private SubscriptionToken? _changedToken; private SubscriptionToken? _syncConflictToken; private ObservableCollection _cards = new(); public ObservableCollection Cards { get => _cards; set => SetProperty(ref _cards, 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? _filterBarcode; public string? FilterBarcode { get => _filterBarcode; set => SetProperty(ref _filterBarcode, value); } private string? _filterBatchNo; public string? FilterBatchNo { get => _filterBatchNo; set => SetProperty(ref _filterBatchNo, value); } private string? _filterMaterialName; public string? FilterMaterialName { get => _filterMaterialName; set => SetProperty(ref _filterMaterialName, value); } private string? _filterSupplierName; public string? FilterSupplierName { get => _filterSupplierName; set => SetProperty(ref _filterSupplierName, value); } private string? _filterStatus; public string? FilterStatus { get => _filterStatus; set => SetProperty(ref _filterStatus, value); } public ObservableCollection> StatusOptions { get; } = new(); public ObservableCollection> TestResultOptions { get; } = new(); public DelegateCommand SearchCommand { get; } public DelegateCommand ResetCommand { get; } public DelegateCommand AddCommand { get; } public DelegateCommand EditCommand { get; } public DelegateCommand DeleteCommand { get; } public DelegateCommand PrintCommand { get; } public DelegateCommand TogglePriorityCommand { get; } public DelegateCommand PrevPageCommand { get; } public DelegateCommand NextPageCommand { get; } public RawMaterialCardListViewModel( IRawMaterialCardService cardService, IJeecgDictSyncService dictSyncService, IPrintDotService printDotService, IContainerExtension container, IRegionManager regionManager) : base(container, regionManager) { _cardService = cardService; _dictSyncService = dictSyncService; _printDotService = printDotService; SearchCommand = new DelegateCommand(async () => { PageNo = 1; await LoadAsync(); }); ResetCommand = new DelegateCommand(async () => { FilterBarcode = null; FilterBatchNo = null; FilterMaterialName = null; FilterSupplierName = null; FilterStatus = null; PageNo = 1; await LoadAsync(); }); AddCommand = new DelegateCommand(async () => await ShowAddDialogAsync()); EditCommand = new DelegateCommand(async c => await ShowEditDialogAsync(c)); DeleteCommand = new DelegateCommand(async c => await DeleteAsync(c)); PrintCommand = new DelegateCommand(async c => await ShowPrintPreviewAsync(c)); TogglePriorityCommand = new DelegateCommand(async c => await TogglePriorityAsync(c)); PrevPageCommand = new DelegateCommand(async () => { if (PageNo > 1) { PageNo--; await LoadAsync(); } }); NextPageCommand = new DelegateCommand(async () => { if ((long)PageNo * PageSize < Total) { PageNo++; await LoadAsync(); } }); _changedToken = _eventAggregator.GetEvent() .Subscribe(async p => await OnChangedAsync(p), ThreadOption.UIThread); _syncConflictToken = _eventAggregator.GetEvent() .Subscribe(OnSyncConflict, ThreadOption.UIThread); _ = InitializeAsync(); } private async Task OnChangedAsync(RawMaterialCardChangedPayload payload) { if (payload.Action == "edit" && !string.IsNullOrWhiteSpace(payload.CardId)) await RefreshSingleAsync(payload.CardId!); else await LoadAsync(); } private async Task RefreshSingleAsync(string cardId) { try { var updated = await _cardService.GetByIdAsync(cardId); if (updated == null) return; var idx = Cards.ToList().FindIndex(c => string.Equals(c.Id, cardId, StringComparison.OrdinalIgnoreCase)); if (idx >= 0) Cards[idx] = updated; } catch (Exception ex) { Debug.WriteLine($"[原材料卡片] 单条刷新失败: {ex.Message}"); } } private void OnSyncConflict(SyncConflictPayload payload) { if (!string.Equals(payload.EntityName, "原材料卡片", StringComparison.OrdinalIgnoreCase)) return; var parts = new List(); if (payload.PushedCount > 0) parts.Add($"已同步 {payload.PushedCount} 条本地改动到服务器"); if (payload.NewRecordsPushed > 0) parts.Add($"已上传 {payload.NewRecordsPushed} 条本地新增记录"); if (payload.ConflictCount > 0) parts.Add($"{payload.ConflictCount} 条记录与服务器版本冲突,已保留服务器版本"); if (parts.Count == 0) return; var message = string.Join("\n", parts); if (payload.ConflictCount > 0) Growl.Warning(message); else Growl.Success(message); } private async Task InitializeAsync() { try { await LoadDictOptionsAsync(); await UIHelper.WaitForRenderAsync(); await LoadAsync(); } catch (Exception ex) { Debug.WriteLine($"[原材料卡片] 初始化失败: {ex.Message}"); } } private async Task LoadDictOptionsAsync() { try { var statusOpts = await _dictSyncService.GetDictOptionsAsync("xslmes_card_status", includeAll: true); var testResultOpts = await _dictSyncService.GetDictOptionsAsync("xslmes_test_result", includeAll: true); StatusOptions.Clear(); foreach (var item in statusOpts) StatusOptions.Add(item); if (StatusOptions.Count == 0) StatusOptions.Add(new KeyValuePair("全部", "")); TestResultOptions.Clear(); foreach (var item in testResultOpts) TestResultOptions.Add(item); if (TestResultOptions.Count == 0) TestResultOptions.Add(new KeyValuePair("全部", "")); } catch { StatusOptions.Clear(); StatusOptions.Add(new KeyValuePair("全部", "")); StatusOptions.Add(new KeyValuePair("正常", "1")); StatusOptions.Add(new KeyValuePair("异常", "0")); TestResultOptions.Clear(); TestResultOptions.Add(new KeyValuePair("全部", "")); TestResultOptions.Add(new KeyValuePair("未检", "0")); TestResultOptions.Add(new KeyValuePair("合格", "1")); TestResultOptions.Add(new KeyValuePair("不合格", "2")); } } public async Task LoadAsync() { try { IsLoading = true; var result = await _cardService.PageAsync(PageNo, PageSize, FilterBarcode, FilterBatchNo, FilterMaterialName, FilterSupplierName, FilterStatus); Cards = 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(MesXslRawMaterialCard card) { if (card == null) return; try { var result = await HandyControl.Controls.Dialog.Show() .Initialize(vm => vm.InitializeForEdit(card)) .GetResultAsync(); if (result) await LoadAsync(); } catch (Exception ex) { Growl.Error($"打开编辑对话框失败:{ex.Message}"); } } private async Task DeleteAsync(MesXslRawMaterialCard card) { if (card?.Id == null) return; var confirm = System.Windows.MessageBox.Show( $"确定删除原材料卡片(条码:{card.Barcode})?此操作不可恢复!", "确认删除", MessageBoxButton.OKCancel, MessageBoxImage.Question); if (confirm != System.Windows.MessageBoxResult.OK) return; var ok = await _cardService.DeleteAsync(card.Id); if (ok) { Growl.Success("删除成功!"); await LoadAsync(); } else Growl.Error("删除失败!"); } private async Task TogglePriorityAsync(MesXslRawMaterialCard card) { if (card?.Id == null) return; var newVal = card.PriorityPickup == "1" ? "0" : "1"; var ok = await _cardService.UpdatePriorityAsync(card.Id, newVal); if (ok) { card.PriorityPickup = newVal; RaisePropertyChanged(nameof(Cards)); } else { Growl.Error("优先出库设置失败!"); } } private async Task ShowPrintPreviewAsync(MesXslRawMaterialCard card) { if (card?.Id == null) return; try { IsLoading = true; var (templateJson, printDataJson, errorMessage) = await _cardService.PrepareNativePrintAsync(card.Id); if (errorMessage != null) { Growl.Error(errorMessage); return; } // 构造一个最简的 PrintTemplate 对象用于传入 PrintPreviewWindow(供显示标题 / 纸张信息) var tpl = BuildPrintTemplateFromJson(templateJson); var win = new PrintPreviewWindow(tpl, templateJson, _printDotService, null, printDataJson) { Owner = Application.Current.MainWindow, WindowStartupLocation = WindowStartupLocation.CenterOwner, }; win.Show(); } catch (Exception ex) { Growl.Error($"打开打印预览失败:{ex.Message}"); } finally { IsLoading = false; } } private static PrintTemplate BuildPrintTemplateFromJson(string templateJson) { try { var root = System.Text.Json.JsonDocument.Parse(templateJson).RootElement; double w = 210, h = 297; if (root.TryGetProperty("page", out var page)) { if (page.TryGetProperty("width", out var wEl)) w = wEl.GetDouble(); if (page.TryGetProperty("height", out var hEl)) h = hEl.GetDouble(); } return new PrintTemplate { TemplateName = "原材料卡片", TemplateCode = "MES_RAW_MATERIAL_CARD", PaperWidthMm = w, PaperHeightMm = h, PaperOrientation = w > h ? "横向" : "纵向", }; } catch { return new PrintTemplate { TemplateName = "原材料卡片", TemplateCode = "MES_RAW_MATERIAL_CARD" }; } } protected override void CleanUp() { base.CleanUp(); if (_changedToken != null) { _eventAggregator.GetEvent().Unsubscribe(_changedToken); _changedToken = null; } if (_syncConflictToken != null) { _eventAggregator.GetEvent().Unsubscribe(_syncConflictToken); _syncConflictToken = null; } } }