新增MES库区管理功能,包含免密接口、数据处理逻辑及相关控制器、服务和实体的实现。支持库区的增删改查操作,优化用户体验并增强系统的实时数据同步能力。

This commit is contained in:
geht
2026-05-12 14:06:07 +08:00
parent cffe32d896
commit b737dddb2a
74 changed files with 4937 additions and 174 deletions

View File

@@ -10,6 +10,7 @@ using YY.Admin.Core;
using YY.Admin.Core.Entity;
using YY.Admin.Core.Events;
using YY.Admin.Core.Services;
using YY.Admin.Core.Util;
namespace YY.Admin.Services.Service.WeightRecord;
@@ -20,6 +21,9 @@ public class WeightRecordService : IWeightRecordService, ISingletonDependency
private readonly INetworkMonitor _networkMonitor;
private readonly IEventAggregator _eventAggregator;
private readonly ILoggerService _logger;
// 用于按 BillNo 实时累计「已入场重量」,从本地入场记录缓存推导,
// 与后端 IMesXslRawMaterialEntryService.sumEnteredWeightByBillNos 同一口径。
private readonly IRawMaterialEntryService _rawMaterialEntryService;
private readonly SemaphoreSlim _syncLock = new(1, 1);
private readonly object _cacheLock = new();
private readonly string _pendingOpsFilePath;
@@ -39,13 +43,15 @@ public class WeightRecordService : IWeightRecordService, ISingletonDependency
IConfiguration configuration,
INetworkMonitor networkMonitor,
IEventAggregator eventAggregator,
ILoggerService logger)
ILoggerService logger,
IRawMaterialEntryService rawMaterialEntryService)
{
_httpClientFactory = httpClientFactory;
_configuration = configuration;
_networkMonitor = networkMonitor;
_eventAggregator = eventAggregator;
_logger = logger;
_rawMaterialEntryService = rawMaterialEntryService;
var appDataDir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
@@ -107,11 +113,49 @@ public class WeightRecordService : IWeightRecordService, ISingletonDependency
var filtered = ApplyFilters(source, filterBillNo, filterPlateNumber, filterInoutDirection, filterDriverName, filterMixerMaterialName);
var total = filtered.Count;
var records = filtered.Skip(Math.Max(0, (pageNo - 1) * pageSize)).Take(pageSize).ToList();
// 当前页结果按本地入场记录缓存,按 BillNo 实时累计「已入场重量」(与后端口径一致)。
// 放在分页之后做:避免对全量 source 做不必要的计算。
FillEnteredWeightFromLocalEntries(records);
return new WeightRecordPageResult(records, total, pageNo, pageSize);
}
/// <summary>
/// 给一批磅单记录批量填充「已入场重量」。
/// 数据来源:本地 RawMaterialEntry 缓存的拆码明细字段totalPortions / portionWeight
/// 与后端 sumEnteredWeightByBillNos 同口径,确保离线场景也能正确显示。
/// </summary>
private void FillEnteredWeightFromLocalEntries(List<MesXslWeightRecord> records)
{
if (records.Count == 0)
{
return;
}
var billNos = records
.Select(r => r.BillNo)
.Where(s => !string.IsNullOrWhiteSpace(s))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
if (billNos.Count == 0)
{
// 全部磅单都没有 BillNo保留服务端返回值若有避免无端置 0。
return;
}
var entries = _rawMaterialEntryService.GetCachedSnapshot();
var sumMap = EnteredWeightCalculator.SumByBillNos(entries, billNos!);
foreach (var r in records)
{
if (string.IsNullOrWhiteSpace(r.BillNo))
{
r.EnteredWeight = 0d;
continue;
}
r.EnteredWeight = sumMap.TryGetValue(r.BillNo, out var v) ? v : 0d;
}
}
public async Task<MesXslWeightRecord?> GetByIdAsync(string id, CancellationToken ct = default)
{
MesXslWeightRecord? record = null;
if (_networkMonitor.IsOnline)
{
try
@@ -119,11 +163,15 @@ public class WeightRecordService : IWeightRecordService, ISingletonDependency
var url = $"{BaseUrl}/xslmes/mesXslWeightRecord/anon/queryById?id={Uri.EscapeDataString(id)}&tenantId={DefaultTenantId}";
using var client = CreateClient();
var resp = await client.GetAsync(url, ct).ConfigureAwait(false);
if (!resp.IsSuccessStatusCode) return null;
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
using var doc = JsonDocument.Parse(json);
if (!doc.RootElement.TryGetProperty("result", out var resultEl)) return null;
return resultEl.Deserialize<MesXslWeightRecord>(_jsonOpts);
if (resp.IsSuccessStatusCode)
{
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
using var doc = JsonDocument.Parse(json);
if (doc.RootElement.TryGetProperty("result", out var resultEl))
{
record = resultEl.Deserialize<MesXslWeightRecord>(_jsonOpts);
}
}
}
catch (Exception ex)
{
@@ -131,11 +179,20 @@ public class WeightRecordService : IWeightRecordService, ISingletonDependency
}
}
lock (_cacheLock)
if (record == null)
{
return _localCache.FirstOrDefault(v => string.Equals(v.Id, id, StringComparison.OrdinalIgnoreCase)) is { } found
? Clone(found) : null;
lock (_cacheLock)
{
record = _localCache.FirstOrDefault(v => string.Equals(v.Id, id, StringComparison.OrdinalIgnoreCase)) is { } found
? Clone(found) : null;
}
}
if (record != null)
{
FillEnteredWeightFromLocalEntries(new List<MesXslWeightRecord> { record });
}
return record;
}
public async Task<bool> AddAsync(MesXslWeightRecord entity, CancellationToken ct = default)
@@ -648,6 +705,8 @@ public class WeightRecordService : IWeightRecordService, ISingletonDependency
GrossWeight = input.GrossWeight,
TareWeight = input.TareWeight,
NetWeight = input.NetWeight,
// 「已入场重量」由实时聚合写入Clone 也要原样传递,避免本地缓存 / Pending 重放后被抹掉
EnteredWeight = input.EnteredWeight,
DriverName = input.DriverName,
DriverPhone = input.DriverPhone,
BillType = input.BillType,