From 50b74f484f5549006e3ed0c82ff87b0026d7350e Mon Sep 17 00:00:00 2001 From: geht <2947093423@qq.com> Date: Mon, 18 May 2026 17:57:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=8E=9F=E6=96=99=E5=85=A5?= =?UTF-8?q?=E5=9C=BA=E6=9D=A1=E7=A0=81=E4=B8=8E=E6=89=B9=E6=AC=A1=E5=8F=B7?= =?UTF-8?q?=E7=94=9F=E6=88=90=E9=80=BB=E8=BE=91=EF=BC=8C=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E6=97=B6=E6=94=AF=E6=8C=81=E6=9C=AC=E5=9C=B0=E5=85=9C=E5=BA=95?= =?UTF-8?q?=EF=BC=9B=E5=B9=B6=E5=9C=A8=E5=90=8E=E7=BB=AD=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=89=8D=E8=A1=A5=E5=85=85=E5=85=A5=E5=9C=BA=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E5=BF=85=E8=A6=81=E6=A0=87=E8=AF=86=E6=A0=A1=E9=AA=8C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/Services/IRawMaterialEntryService.cs | 2 +- .../RawMaterialEntryService.cs | 48 ++++++++++++++++++- .../RawMaterialEntryOperationViewModel.cs | 41 ++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/yy-admin-master/YY.Admin.Core/Core/Services/IRawMaterialEntryService.cs b/yy-admin-master/YY.Admin.Core/Core/Services/IRawMaterialEntryService.cs index 5ef9882..e6930c8 100644 --- a/yy-admin-master/YY.Admin.Core/Core/Services/IRawMaterialEntryService.cs +++ b/yy-admin-master/YY.Admin.Core/Core/Services/IRawMaterialEntryService.cs @@ -21,7 +21,7 @@ public interface IRawMaterialEntryService Task DeleteAsync(string id, CancellationToken ct = default); Task DeleteBatchAsync(string ids, CancellationToken ct = default); - /// 调用后端接口生成条码/批次号(格式:QH+物料编码+yyMMdd+序号) + /// 生成条码/批次号(优先后端,离线回退本地;格式:QH+物料编码+yyMMdd+序号) Task GenerateBarcodeAsync(string materialCode, CancellationToken ct = default); /// 按业务打印绑定准备模板 JSON 与 printData(与后端 prepareNativePrint 一致,免密 anon)。 diff --git a/yy-admin-master/YY.Admin.Services/Service/RawMaterialEntry/RawMaterialEntryService.cs b/yy-admin-master/YY.Admin.Services/Service/RawMaterialEntry/RawMaterialEntryService.cs index 37ceef6..5cf493e 100644 --- a/yy-admin-master/YY.Admin.Services/Service/RawMaterialEntry/RawMaterialEntryService.cs +++ b/yy-admin-master/YY.Admin.Services/Service/RawMaterialEntry/RawMaterialEntryService.cs @@ -5,6 +5,7 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Serialization; +using System.Globalization; using System.Web; using Prism.Events; using YY.Admin.Core; @@ -151,6 +152,7 @@ public class RawMaterialEntryService : IRawMaterialEntryService, ISingletonDepen if (!entry.TenantId.HasValue || entry.TenantId.Value <= 0) entry.TenantId = DefaultTenantId; var local = Clone(entry); if (string.IsNullOrWhiteSpace(local.Id)) local.Id = $"local-{Guid.NewGuid():N}"; + EnsureBarcodeAndBatchNo(local); if (_networkMonitor.IsOnline) { @@ -228,6 +230,11 @@ public class RawMaterialEntryService : IRawMaterialEntryService, ISingletonDepen public async Task GenerateBarcodeAsync(string materialCode, CancellationToken ct = default) { + if (!_networkMonitor.IsOnline) + { + return GenerateLocalBarcode(materialCode); + } + var url = $"{BaseUrl}/xslmes/mesXslRawMaterialEntry/anon/generateBarcode?materialCode={Uri.EscapeDataString(materialCode ?? "")}"; try { @@ -243,7 +250,46 @@ public class RawMaterialEntryService : IRawMaterialEntryService, ISingletonDepen { _logger.Warning($"[原料入场] 生成条码失败: {ex.Message}"); } - return null; + return GenerateLocalBarcode(materialCode); + } + + /// + /// 桌面端离线兜底产号:保持与服务端一致的格式 QH + 物料编码 + yyMMdd + 3位流水。 + /// 流水号口径与服务端一致:按当前前缀匹配条码计数 + 1(非 max+1)。 + /// + private string GenerateLocalBarcode(string materialCode) + { + var normalizedCode = (materialCode ?? string.Empty).Trim(); + var dateStr = DateTime.Now.ToString("yyMMdd", CultureInfo.InvariantCulture); + var prefix = $"QH{normalizedCode}{dateStr}"; + + int sequence; + lock (_cacheLock) + { + var snapshot = ApplyPendingOpsSnapshotUnsafe(_localCache.Select(Clone).ToList()); + var count = snapshot.Count(x => + !string.IsNullOrWhiteSpace(x.Barcode) && + x.Barcode!.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)); + sequence = count + 1; + } + return $"{prefix}{sequence:000}"; + } + + /// + /// 新增入场记录时保证条码和批次号本地可用: + /// 条码为空时本地生成,批次号为空时回填为条码。 + /// + private void EnsureBarcodeAndBatchNo(MesXslRawMaterialEntry entry) + { + if (string.IsNullOrWhiteSpace(entry.Barcode)) + { + entry.Barcode = GenerateLocalBarcode(entry.MaterialCode ?? string.Empty); + } + + if (string.IsNullOrWhiteSpace(entry.BatchNo)) + { + entry.BatchNo = entry.Barcode; + } } public async Task<(string templateJson, string printDataJson, string? errorMessage)> PrepareNativePrintAsync(string id, CancellationToken ct = default) diff --git a/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/RawMaterialEntryOperationViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/RawMaterialEntryOperationViewModel.cs index ae9a88d..103ecb3 100644 --- a/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/RawMaterialEntryOperationViewModel.cs +++ b/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/RawMaterialEntryOperationViewModel.cs @@ -688,6 +688,11 @@ public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogView return; } + if (!await EnsureEntryBarcodeAndBatchNoAsync()) + { + return; + } + // 库位必填仅校验本批待生成行;行号取在原集合的真实索引,避免编号偏移误导 foreach (var row in pendingRows) { @@ -865,6 +870,42 @@ public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogView } } + /// + /// 生成原材料卡片前确保入场记录已有条码/批次号。 + /// 规则:条码优先沿用现有值;为空时调用入场服务生成(在线优先,离线本地兜底); + /// 批次号为空则回填为条码。 + /// + private async Task EnsureEntryBarcodeAndBatchNoAsync() + { + if (Entry == null) return false; + + if (string.IsNullOrWhiteSpace(Entry.Barcode)) + { + if (string.IsNullOrWhiteSpace(Entry.MaterialCode)) + { + HandyControl.Controls.MessageBox.Warning("当前记录缺少物料编码,无法生成原材料卡片条码。"); + return false; + } + + var code = await EntryService.GenerateBarcodeAsync(Entry.MaterialCode); + if (string.IsNullOrWhiteSpace(code)) + { + HandyControl.Controls.MessageBox.Warning("未能生成入场条码,请检查网络或稍后重试。"); + return false; + } + + Entry.Barcode = code.Trim(); + } + + if (string.IsNullOrWhiteSpace(Entry.BatchNo)) + { + Entry.BatchNo = Entry.Barcode; + } + + RaisePropertyChanged(nameof(Entry)); + return true; + } + private List BuildPlannedRawMaterialCards( MesXslRawMaterialEntry entry, IReadOnlyList pendingRows,