桌面端原材料入场记录完善
This commit is contained in:
@@ -8,6 +8,7 @@ using System.Globalization;
|
||||
using YY.Admin.Core;
|
||||
using YY.Admin.Core.Entity;
|
||||
using YY.Admin.Core.Services;
|
||||
using YY.Admin.Core.Util;
|
||||
using YY.Admin.Services.Service;
|
||||
using YY.Admin.Services.Service.MixerMaterialTareStrategy;
|
||||
using YY.Admin.Views.RawMaterialEntry;
|
||||
@@ -25,6 +26,7 @@ public class RawMaterialEntryEditDialogViewModel : BaseViewModel, IDialogResulta
|
||||
private readonly IMixerMaterialService _mixerMaterialService;
|
||||
private readonly IMixerMaterialTareStrategyService _tareStrategyService;
|
||||
private readonly ISupplierService _supplierService;
|
||||
private readonly IWeightRecordService _weightRecordService;
|
||||
private bool _suppressTareStrategyRefresh;
|
||||
protected string? _pendingMaterialId;
|
||||
|
||||
@@ -212,6 +214,7 @@ public class RawMaterialEntryEditDialogViewModel : BaseViewModel, IDialogResulta
|
||||
IMixerMaterialService mixerMaterialService,
|
||||
IMixerMaterialTareStrategyService tareStrategyService,
|
||||
ISupplierService supplierService,
|
||||
IWeightRecordService weightRecordService,
|
||||
IContainerExtension container,
|
||||
IRegionManager regionManager) : base(container, regionManager)
|
||||
{
|
||||
@@ -220,6 +223,7 @@ public class RawMaterialEntryEditDialogViewModel : BaseViewModel, IDialogResulta
|
||||
_mixerMaterialService = mixerMaterialService;
|
||||
_tareStrategyService = tareStrategyService;
|
||||
_supplierService = supplierService;
|
||||
_weightRecordService = weightRecordService;
|
||||
SaveCommand = new DelegateCommand(async () => await SaveAsync());
|
||||
CancelCommand = new DelegateCommand(() => CloseAction?.Invoke());
|
||||
ResetCommand = new DelegateCommand(InitializeForAdd);
|
||||
@@ -468,6 +472,10 @@ public class RawMaterialEntryEditDialogViewModel : BaseViewModel, IDialogResulta
|
||||
return false;
|
||||
}
|
||||
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】新增/加量前校验磅单剩余净重-----------
|
||||
if (!await ValidateBillRemainingWeightAsync()) return false;
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】新增/加量前校验磅单剩余净重-----------
|
||||
|
||||
bool ok;
|
||||
if (IsAddMode)
|
||||
{
|
||||
@@ -483,6 +491,69 @@ public class RawMaterialEntryEditDialogViewModel : BaseViewModel, IDialogResulta
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验关联磅单剩余可入场量:剩余 = 净重 - 其他已存在入场记录累计(份数×每份重量)。
|
||||
/// 剩余 ≤ 0 或本次申请量超过剩余时禁止保存。编辑时排除当前记录自身。
|
||||
/// </summary>
|
||||
protected async Task<bool> ValidateBillRemainingWeightAsync()
|
||||
{
|
||||
if (Entry == null || string.IsNullOrWhiteSpace(Entry.BillNo)) return true;
|
||||
|
||||
// 先刷新入场缓存,保证已入场累计与远端一致
|
||||
await _entryService.PageAsync(1, 1, billNo: Entry.BillNo);
|
||||
|
||||
MesXslWeightRecord? weightRecord = null;
|
||||
if (!string.IsNullOrWhiteSpace(Entry.WeightRecordId))
|
||||
{
|
||||
weightRecord = await _weightRecordService.GetByIdAsync(Entry.WeightRecordId);
|
||||
}
|
||||
if (weightRecord == null)
|
||||
{
|
||||
var page = await _weightRecordService.PageAsync(1, 5, filterBillNo: Entry.BillNo);
|
||||
weightRecord = page.Records.FirstOrDefault(r =>
|
||||
string.Equals(r.BillNo, Entry.BillNo, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
if (weightRecord?.NetWeight is not { } netWeight)
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Warning("关联磅单缺少净重,无法校验剩余可入场量,禁止保存。");
|
||||
return false;
|
||||
}
|
||||
|
||||
var others = _entryService.GetCachedSnapshot()
|
||||
.Where(e => !string.IsNullOrWhiteSpace(e.BillNo)
|
||||
&& string.Equals(e.BillNo, Entry.BillNo, StringComparison.OrdinalIgnoreCase)
|
||||
&& (string.IsNullOrWhiteSpace(Entry.Id)
|
||||
|| !string.Equals(e.Id, Entry.Id, StringComparison.OrdinalIgnoreCase)))
|
||||
.ToList();
|
||||
var enteredMap = EnteredWeightCalculator.SumByBillNos(others, new[] { Entry.BillNo });
|
||||
var entered = enteredMap.TryGetValue(Entry.BillNo, out var acc) ? acc : 0d;
|
||||
var remaining = Math.Round(netWeight - entered, 2);
|
||||
|
||||
var requested = EnteredWeightCalculator.SumOneEntry(Entry.TotalPortions, Entry.PortionWeight);
|
||||
if (requested <= 0d && Entry.TotalWeight is { } tw && tw > 0d)
|
||||
{
|
||||
requested = tw;
|
||||
}
|
||||
requested = Math.Round(requested, 2);
|
||||
|
||||
if (remaining <= 0d)
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Warning(
|
||||
$"关联磅单「{Entry.BillNo}」净重已被已有入场记录扣完(净重 {netWeight:0.##},已入场 {entered:0.##}),不能再生成入场记录。");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (requested > remaining + 0.009d)
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Warning(
|
||||
$"本次入场重量 {requested:0.##} 超过磅单剩余可入场量 {remaining:0.##}(净重 {netWeight:0.##},已入场 {entered:0.##}),请调整后再保存。");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual async Task SaveAsync()
|
||||
{
|
||||
if (Entry == null) return;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using HandyControl.Controls;
|
||||
using HandyControl.Tools.Extension;
|
||||
using Prism.Events;
|
||||
using Prism.Navigation;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
@@ -12,7 +12,6 @@ using YY.Admin.Core.Services;
|
||||
using YY.Admin.Event;
|
||||
using YY.Admin.Services.Service;
|
||||
using YY.Admin.Module;
|
||||
using YY.Admin.Views.RawMaterialEntry;
|
||||
|
||||
namespace YY.Admin.ViewModels.RawMaterialEntry;
|
||||
|
||||
@@ -80,7 +79,9 @@ public class RawMaterialEntryListViewModel : BaseViewModel
|
||||
await LoadAsync();
|
||||
});
|
||||
AddCommand = new DelegateCommand(OpenAddPage);
|
||||
EditCommand = new DelegateCommand<MesXslRawMaterialEntry>(async e => await ShowEditDialogAsync(e));
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】编辑改为打开与新增相同的操作页-----------
|
||||
EditCommand = new DelegateCommand<MesXslRawMaterialEntry>(OpenEditPage);
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】编辑改为打开与新增相同的操作页-----------
|
||||
DeleteCommand = new DelegateCommand<MesXslRawMaterialEntry>(async e => await DeleteAsync(e));
|
||||
PrevPageCommand = new DelegateCommand(async () => { if (PageNo > 1) { PageNo--; await LoadAsync(); } });
|
||||
NextPageCommand = new DelegateCommand(async () => { if ((long)PageNo * PageSize < Total) { PageNo++; await LoadAsync(); } });
|
||||
@@ -161,18 +162,21 @@ public class RawMaterialEntryListViewModel : BaseViewModel
|
||||
});
|
||||
}
|
||||
|
||||
private async Task ShowEditDialogAsync(MesXslRawMaterialEntry entry)
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】编辑改为打开与新增相同的操作页-----------
|
||||
private void OpenEditPage(MesXslRawMaterialEntry? entry)
|
||||
{
|
||||
if (entry == null) return;
|
||||
try
|
||||
if (entry == null || string.IsNullOrWhiteSpace(entry.Id)) return;
|
||||
|
||||
var label = string.IsNullOrWhiteSpace(entry.Barcode) ? entry.Id : entry.Barcode;
|
||||
_eventAggregator.GetEvent<TabSourceSelectedEvent>().Publish(new TabSource
|
||||
{
|
||||
var result = await HandyControl.Controls.Dialog.Show<RawMaterialEntryEditDialogView>()
|
||||
.Initialize<RawMaterialEntryEditDialogViewModel>(vm => vm.InitializeForEdit(entry))
|
||||
.GetResultAsync<bool>();
|
||||
if (result) await LoadAsync();
|
||||
}
|
||||
catch (Exception ex) { Growl.Error($"打开编辑对话框失败:{ex.Message}"); }
|
||||
Name = $"编辑原料入场记录 {label}",
|
||||
Icon = "\ue7ce",
|
||||
ViewName = "RawMaterialEntryOperationView",
|
||||
NavigationParameter = new NavigationParameters { { "editEntryId", entry.Id } }
|
||||
});
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】编辑改为打开与新增相同的操作页-----------
|
||||
|
||||
private async Task DeleteAsync(MesXslRawMaterialEntry entry)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using HandyControl.Controls;
|
||||
using HandyControl.Data;
|
||||
using Prism.Commands;
|
||||
using Prism.Navigation;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
@@ -18,9 +19,9 @@ using YY.Admin.Views.RawMaterialEntry;
|
||||
namespace YY.Admin.ViewModels.RawMaterialEntry;
|
||||
|
||||
/// <summary>
|
||||
/// 「新增原料入场记录」独立页面:左侧表单逻辑继承编辑 VM,右侧展示当日入场简要列表并支持选中回填模板。
|
||||
/// 原料入场记录独立操作页(新增/编辑共用):左侧表单,右侧当日入场列表与打印预览。
|
||||
/// </summary>
|
||||
public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogViewModel
|
||||
public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogViewModel, INavigationAware
|
||||
{
|
||||
private const int TodayListFetchSize = 5000;
|
||||
private const string RawMaterialEntryBizCode = "1900000000000000530";
|
||||
@@ -30,6 +31,11 @@ public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogView
|
||||
private readonly IPrintDotService _printDotService;
|
||||
private readonly IPrintBizTemplateBindService _printBizTemplateBindService;
|
||||
private readonly IPrintTemplateService _printTemplateService;
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】操作页支持导航进入编辑态-----------
|
||||
private string? _editingEntryId;
|
||||
/// <summary>是否已由 INavigationAware 处理过导航参数(避免 Loaded 兜底把编辑态冲掉)。</summary>
|
||||
public bool HasAppliedNavigation { get; private set; }
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】操作页支持导航进入编辑态-----------
|
||||
|
||||
private static readonly JsonSerializerOptions LayoutJsonOpts = new()
|
||||
{
|
||||
@@ -98,12 +104,28 @@ public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogView
|
||||
|
||||
/// <summary>
|
||||
/// 「生成原材料卡片」按钮可用条件:
|
||||
/// 入场记录已保存(有 Id)且至少存在一行「未生成卡片 + 份数>0」的明细。
|
||||
/// 已打印态下用户「继续拆码」新增了行,按钮自动重新可用;全部行都已生成卡片时不可用。
|
||||
/// 入场记录已保存(有 Id)且至少存在一行「未生成卡片 + 份数>0」的明细,
|
||||
/// 且入场总重尚未被已打印卡片扣完。
|
||||
/// </summary>
|
||||
public bool CanGenerateCards =>
|
||||
!string.IsNullOrWhiteSpace(Entry?.Id)
|
||||
&& SplitCodeDetails.Any(d => !d.HasCard && (d.Portions ?? 0) > 0);
|
||||
&& SplitCodeDetails.Any(d => !d.HasCard && (d.Portions ?? 0) > 0)
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】已打印卡片扣完总重后禁用生成-----------
|
||||
&& GetEntryRemainingWeightForCards() > 0.009d;
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】已打印卡片扣完总重后禁用生成-----------
|
||||
|
||||
/// <summary>已打印卡片累计重量 = Σ(HasCard 行 份数×每份重量)。</summary>
|
||||
private double GetPrintedCardsWeight() =>
|
||||
SplitCodeDetails
|
||||
.Where(d => d.HasCard)
|
||||
.Sum(d => (d.PortionWeight ?? 0d) * (d.Portions ?? 0));
|
||||
|
||||
/// <summary>入场总重减去已打印卡片累计后的剩余可打印重量。</summary>
|
||||
private double GetEntryRemainingWeightForCards()
|
||||
{
|
||||
var total = Entry?.TotalWeight ?? 0d;
|
||||
return Math.Round(total - GetPrintedCardsWeight(), 2);
|
||||
}
|
||||
|
||||
public DelegateCommand ToggleRightPanelCommand { get; }
|
||||
public DelegateCommand RefreshTodayEntriesCommand { get; }
|
||||
@@ -244,13 +266,14 @@ public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogView
|
||||
IMixerMaterialService mixerMaterialService,
|
||||
IMixerMaterialTareStrategyService tareStrategyService,
|
||||
ISupplierService supplierService,
|
||||
IWeightRecordService weightRecordService,
|
||||
IRawMaterialCardService rawMaterialCardService,
|
||||
IPrintDotService printDotService,
|
||||
IPrintBizTemplateBindService printBizTemplateBindService,
|
||||
IPrintTemplateService printTemplateService,
|
||||
IContainerExtension container,
|
||||
IRegionManager regionManager)
|
||||
: base(entryService, dictSyncService, mixerMaterialService, tareStrategyService, supplierService, container, regionManager)
|
||||
: base(entryService, dictSyncService, mixerMaterialService, tareStrategyService, supplierService, weightRecordService, container, regionManager)
|
||||
{
|
||||
_rawMaterialCardService = rawMaterialCardService;
|
||||
_printDotService = printDotService;
|
||||
@@ -314,7 +337,10 @@ public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogView
|
||||
private void OnSplitDetailHasCardChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName is nameof(RawMaterialSplitDetailItem.HasCard)
|
||||
or nameof(RawMaterialSplitDetailItem.Portions))
|
||||
or nameof(RawMaterialSplitDetailItem.Portions)
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】每份重量变化同步刷新可生成状态-----------
|
||||
or nameof(RawMaterialSplitDetailItem.PortionWeight))
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】每份重量变化同步刷新可生成状态-----------
|
||||
{
|
||||
RaisePropertyChanged(nameof(CanGenerateCards));
|
||||
RaisePropertyChanged(nameof(CanResplit));
|
||||
@@ -329,71 +355,175 @@ public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogView
|
||||
_selectedTodayEntry = null;
|
||||
RaisePropertyChanged(nameof(SelectedTodayEntry));
|
||||
_suppressTodaySelectionReaction = false;
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】切回新增态时清除编辑导航标记-----------
|
||||
_editingEntryId = null;
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】切回新增态时清除编辑导航标记-----------
|
||||
base.InitializeForAdd();
|
||||
RaisePropertyChanged(nameof(CanGenerateCards));
|
||||
}
|
||||
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】操作页支持导航进入编辑态-----------
|
||||
public void OnNavigatedTo(NavigationContext navigationContext)
|
||||
{
|
||||
HasAppliedNavigation = true;
|
||||
_ = ApplyNavigationAsync(navigationContext.Parameters);
|
||||
}
|
||||
|
||||
public bool IsNavigationTarget(NavigationContext navigationContext)
|
||||
{
|
||||
var parameters = navigationContext.Parameters;
|
||||
if (parameters.TryGetValue<string>("editEntryId", out var editId) && !string.IsNullOrWhiteSpace(editId))
|
||||
return string.Equals(_editingEntryId, editId, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return string.IsNullOrWhiteSpace(_editingEntryId) && IsAddMode;
|
||||
}
|
||||
|
||||
public void OnNavigatedFrom(NavigationContext navigationContext) { }
|
||||
|
||||
private async Task ApplyNavigationAsync(INavigationParameters parameters)
|
||||
{
|
||||
if (parameters.TryGetValue<string>("editEntryId", out var editId) && !string.IsNullOrWhiteSpace(editId))
|
||||
{
|
||||
_editingEntryId = editId;
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
var entry = await EntryService.GetByIdAsync(editId);
|
||||
if (entry == null)
|
||||
{
|
||||
Growl.Warning($"未找到入场记录(Id={editId}),已切换为新增。");
|
||||
InitializeForAdd();
|
||||
return;
|
||||
}
|
||||
|
||||
await ApplyTodayRowToFormAsync(entry);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Growl.Error($"加载入场记录失败:{ex.Message}");
|
||||
InitializeForAdd();
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_editingEntryId = null;
|
||||
InitializeForAdd();
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】操作页支持导航进入编辑态-----------
|
||||
|
||||
/// <summary>保存后按业务打印绑定拉取模板与 printData,直接发送到 PrintDot 打印机(不弹预览窗)。</summary>
|
||||
private async Task SaveAndPrintAsync()
|
||||
{
|
||||
if (IsActionBusy) return;
|
||||
if (Entry == null) return;
|
||||
var wasEdit = !IsAddMode;
|
||||
var barcode = Entry.Barcode;
|
||||
BeginActionBusy("保存并打印中...");
|
||||
// 新增模式下:打印失败必须回滚删除刚生成的入场记录,避免“未打印成功却已落库”
|
||||
var createdInThisAttempt = IsAddMode;
|
||||
string? createdEntryId = null;
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
if (!await PersistEntryCoreAsync()) return;
|
||||
|
||||
string? entryId = Entry.Id;
|
||||
// Persist 后条码/主键可能已回写,再取一次
|
||||
var barcode = Entry?.Barcode;
|
||||
string? entryId = Entry?.Id;
|
||||
if (string.IsNullOrWhiteSpace(entryId) && !string.IsNullOrWhiteSpace(barcode))
|
||||
{
|
||||
var page = await EntryService.PageAsync(1, 50, barcode: barcode);
|
||||
entryId = page.Records
|
||||
entryId = page.Records?
|
||||
.FirstOrDefault(e => string.Equals(e.Barcode, barcode, StringComparison.OrdinalIgnoreCase))?.Id
|
||||
?? page.Records
|
||||
?? page.Records?
|
||||
.OrderByDescending(e => e.EntryTime ?? e.CreateTime ?? DateTime.MinValue)
|
||||
.FirstOrDefault()?.Id;
|
||||
if (!string.IsNullOrWhiteSpace(entryId) && Entry != null)
|
||||
Entry.Id = entryId;
|
||||
}
|
||||
|
||||
if (createdInThisAttempt)
|
||||
createdEntryId = entryId;
|
||||
|
||||
async Task RollbackCreatedAsync(string reason)
|
||||
{
|
||||
if (!createdInThisAttempt || string.IsNullOrWhiteSpace(createdEntryId))
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Error(reason);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await EntryService.DeleteAsync(createdEntryId);
|
||||
if (Entry != null)
|
||||
{
|
||||
Entry.Id = null;
|
||||
Entry.Barcode = null;
|
||||
Entry.BatchNo = null;
|
||||
}
|
||||
Result = false;
|
||||
await LoadTodayEntriesAsync();
|
||||
}
|
||||
catch (Exception delEx)
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Error(
|
||||
$"{reason}\n同时回滚删除入场记录失败:{delEx.Message}\n请手动删除刚生成的记录。");
|
||||
return;
|
||||
}
|
||||
|
||||
HandyControl.Controls.MessageBox.Error($"{reason}\n已撤销本次入场记录,未成功打印不会保留数据。");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(entryId))
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Warning("保存成功,但未能解析记录主键,无法打印。请从右侧列表选中该条后再试。");
|
||||
await RollbackCreatedAsync("保存后未能解析记录主键,无法打印。");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
var (templateJson, printDataJson, err) = await EntryService.PrepareNativePrintAsync(entryId);
|
||||
if (!string.IsNullOrWhiteSpace(err))
|
||||
{
|
||||
var (templateJson, printDataJson, err) = await EntryService.PrepareNativePrintAsync(entryId);
|
||||
if (!string.IsNullOrWhiteSpace(err))
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Error($"保存成功,但打印准备失败:{err}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedPrinterName = SelectedPrinter?.Name?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(selectedPrinterName))
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Warning("保存成功,但未选择打印机。请先选择打印机后再试。");
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonObject? dataObj = JsonNode.Parse(printDataJson) as JsonObject;
|
||||
dataObj ??= new JsonObject();
|
||||
var html = NativePrintRenderService.RenderToHtml(templateJson, dataObj);
|
||||
var tpl = BuildPrintTemplateForEntry(templateJson);
|
||||
var pdfBase64 = await HtmlToPdfRenderer.RenderAsync(
|
||||
html,
|
||||
tpl.PaperWidthMm ?? 210d,
|
||||
tpl.PaperHeightMm ?? 297d);
|
||||
var jobName = string.IsNullOrWhiteSpace(barcode) ? "原料入场记录" : $"原料入场记录-{barcode}";
|
||||
await _printDotService.PrintAsync(selectedPrinterName, pdfBase64, jobName, 1);
|
||||
}
|
||||
}
|
||||
await RollbackCreatedAsync($"打印准备失败:{err}");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(templateJson))
|
||||
{
|
||||
await RollbackCreatedAsync("打印模板为空,请先配置业务打印绑定。");
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedPrinterName = SelectedPrinter?.Name?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(selectedPrinterName))
|
||||
{
|
||||
await RollbackCreatedAsync("未选择打印机,请先选择打印机后再试。");
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject? dataObj = null;
|
||||
if (!string.IsNullOrWhiteSpace(printDataJson))
|
||||
dataObj = JsonNode.Parse(printDataJson) as JsonObject;
|
||||
dataObj ??= new JsonObject();
|
||||
var html = NativePrintRenderService.RenderToHtml(templateJson, dataObj);
|
||||
var tpl = BuildPrintTemplateForEntry(templateJson);
|
||||
var pdfBase64 = await HtmlToPdfRenderer.RenderAsync(
|
||||
html,
|
||||
tpl.PaperWidthMm ?? 210d,
|
||||
tpl.PaperHeightMm ?? 297d);
|
||||
if (string.IsNullOrWhiteSpace(pdfBase64))
|
||||
{
|
||||
await RollbackCreatedAsync("PDF 生成结果为空,打印失败。");
|
||||
return;
|
||||
}
|
||||
|
||||
var jobName = string.IsNullOrWhiteSpace(barcode) ? "原料入场记录" : $"原料入场记录-{barcode}";
|
||||
await _printDotService.PrintAsync(selectedPrinterName, pdfBase64, jobName, 1);
|
||||
|
||||
Growl.Success(new GrowlInfo
|
||||
{
|
||||
Message = "保存成功",
|
||||
Message = "保存并打印成功",
|
||||
ShowDateTime = false,
|
||||
WaitTime = 1
|
||||
});
|
||||
@@ -405,7 +535,33 @@ public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogView
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Error($"保存或打印失败:{ex.Message}");
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】保存并打印失败时回滚新增记录-----------
|
||||
if (createdInThisAttempt && !string.IsNullOrWhiteSpace(createdEntryId))
|
||||
{
|
||||
try
|
||||
{
|
||||
await EntryService.DeleteAsync(createdEntryId);
|
||||
if (Entry != null)
|
||||
{
|
||||
Entry.Id = null;
|
||||
Entry.Barcode = null;
|
||||
Entry.BatchNo = null;
|
||||
}
|
||||
Result = false;
|
||||
await LoadTodayEntriesAsync();
|
||||
HandyControl.Controls.MessageBox.Error($"打印失败:{ex.Message}\n已撤销本次入场记录,未成功打印不会保留数据。");
|
||||
}
|
||||
catch (Exception delEx)
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Error(
|
||||
$"打印失败:{ex.Message}\n同时回滚删除入场记录失败:{delEx.Message}\n请手动删除刚生成的记录。");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Error($"保存或打印失败:{ex.Message}");
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】保存并打印失败时回滚新增记录-----------
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -536,6 +692,9 @@ public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogView
|
||||
private async Task ApplyTodayRowToFormAsync(MesXslRawMaterialEntry src)
|
||||
{
|
||||
// 复用基类 InitializeForEdit:保留 Id/Barcode/BatchNo/状态等所有字段,标题自动切到「编辑原料入场记录」
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】今日列表选中同步编辑导航标记-----------
|
||||
_editingEntryId = src.Id;
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】今日列表选中同步编辑导航标记-----------
|
||||
base.InitializeForEdit(src);
|
||||
RaisePropertyChanged(nameof(CanGenerateCards));
|
||||
|
||||
@@ -706,17 +865,36 @@ public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogView
|
||||
}
|
||||
}
|
||||
|
||||
// 总重核对:拆码明细合计 vs 基础资料总重
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】已打印卡片扣完总重禁止再打印-----------
|
||||
{
|
||||
var entryTotal = Entry.TotalWeight ?? 0d;
|
||||
var printedWeight = Math.Round(GetPrintedCardsWeight(), 2);
|
||||
var remaining = Math.Round(entryTotal - printedWeight, 2);
|
||||
if (remaining <= 0d)
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Warning(
|
||||
$"入场总重 {entryTotal:0.##} 已被已打印原材料卡片总重 {printedWeight:0.##} 扣完,不能再打印原材料卡片。");
|
||||
return;
|
||||
}
|
||||
|
||||
var pendingWeight = Math.Round(
|
||||
pendingRows.Sum(d => (d.PortionWeight ?? 0d) * (d.Portions ?? 0)), 2);
|
||||
if (pendingWeight > remaining + 0.009d)
|
||||
{
|
||||
HandyControl.Controls.MessageBox.Warning(
|
||||
$"待打印卡片总重 {pendingWeight:0.##} 超过剩余可打印重量 {remaining:0.##}(入场总重 {entryTotal:0.##},已打印 {printedWeight:0.##}),请调整拆码明细后再生成。");
|
||||
return;
|
||||
}
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】已打印卡片扣完总重禁止再打印-----------
|
||||
|
||||
// 总重核对:拆码明细合计 vs 基础资料总重(剩余不足时上面已硬拦截;此处仅提示拆码合计偏少)
|
||||
{
|
||||
var splitTotal = SplitCodeDetails.Sum(d => (d.PortionWeight ?? 0d) * (d.Portions ?? 0));
|
||||
var basicTotal = Entry.TotalWeight ?? 0d;
|
||||
if (Math.Abs(splitTotal - basicTotal) > 0.01d)
|
||||
if (basicTotal - splitTotal > 0.01d)
|
||||
{
|
||||
string hint;
|
||||
if (splitTotal > basicTotal)
|
||||
hint = $"本次打印拆码总重 {splitTotal:0.##},超出基础资料总重 {basicTotal:0.##},超出部分是否需要核对?";
|
||||
else
|
||||
hint = $"本次打印拆码总重 {splitTotal:0.##},少于基础资料总重 {basicTotal:0.##},剩余部分将无法继续拆码,是否继续?";
|
||||
var hint = $"本次打印拆码总重 {splitTotal:0.##},少于基础资料总重 {basicTotal:0.##},剩余部分将无法继续拆码,是否继续?";
|
||||
var confirm = System.Windows.MessageBox.Show(
|
||||
hint,
|
||||
"总重核对",
|
||||
|
||||
Reference in New Issue
Block a user