新增密炼物料皮重策略功能,包括相关实体、服务、控制器及接口,支持桌面端免密CRUD操作,优化打印记录与原料入场记录的衍生字段填充逻辑,提升用户体验。

This commit is contained in:
geht
2026-06-02 16:28:51 +08:00
parent 37239e1b0a
commit fef7d25e3c
75 changed files with 4407 additions and 170 deletions

View File

@@ -0,0 +1,11 @@
using Prism.Events;
namespace YY.Admin.Core.Events;
public class MixerMaterialTareStrategyChangedPayload
{
public string Action { get; set; } = string.Empty;
public string? TareStrategyId { get; set; }
}
public class MixerMaterialTareStrategyChangedEvent : PubSubEvent<MixerMaterialTareStrategyChangedPayload> { }

View File

@@ -0,0 +1,28 @@
using YY.Admin.Core.Entity;
namespace YY.Admin.Core.Services;
public interface IMixerMaterialTareStrategyService
{
Task<MixerMaterialTareStrategyPageResult> PageAsync(
int pageNo,
int pageSize,
string? mixerMaterialName = null,
string? supplierName = null,
CancellationToken ct = default);
Task<MesXslMixerMaterialTareStrategy?> GetByIdAsync(string id, CancellationToken ct = default);
Task<bool> AddAsync(MesXslMixerMaterialTareStrategy strategy, CancellationToken ct = default);
Task<bool> EditAsync(MesXslMixerMaterialTareStrategy strategy, CancellationToken ct = default);
Task<bool> DeleteAsync(string id, CancellationToken ct = default);
Task<List<MesXslUnit>> GetUnitsAsync(CancellationToken ct = default);
/// <summary>拉取全部策略(用于原料入场拆码明细自动/手动匹配)。</summary>
Task<IReadOnlyList<MesXslMixerMaterialTareStrategy>> GetAllForMatchAsync(CancellationToken ct = default);
}
public record MixerMaterialTareStrategyPageResult(
List<MesXslMixerMaterialTareStrategy> Records,
long Total,
int PageNo,
int PageSize);

View File

@@ -0,0 +1,31 @@
namespace YY.Admin.Core.Entity;
public class MesXslMixerMaterialTareStrategy
{
public string? Id { get; set; }
public int? TenantId { get; set; }
public string? MixerMaterialId { get; set; }
public string? MixerMaterialName { get; set; }
public string? SupplierId { get; set; }
public string? SupplierName { get; set; }
public string? MaterialSpec { get; set; }
public decimal? TareWeight { get; set; }
public decimal? PalletWeight { get; set; }
public string? UnitId { get; set; }
public string? UnitName { get; set; }
public DateTime? EffectiveStartDate { get; set; }
public DateTime? EffectiveEndDate { get; set; }
public string? MaintainBy { get; set; }
public string? CreateBy { get; set; }
public DateTime? CreateTime { get; set; }
public string? UpdateBy { get; set; }
public DateTime? UpdateTime { get; set; }
public string? SysOrgCode { get; set; }
public int? DelFlag { get; set; }
public string EffectiveStartDateText =>
EffectiveStartDate?.ToString("yyyy-MM-dd") ?? string.Empty;
public string EffectiveEndDateText =>
EffectiveEndDate?.ToString("yyyy-MM-dd") ?? string.Empty;
}

View File

@@ -17,6 +17,10 @@ public class MesXslRawMaterialCard
public string? ManufacturerMaterialName { get; set; }
public string? ShelfLife { get; set; }
public decimal? TotalWeight { get; set; }
/// <summary>包装物皮重(KG)</summary>
public decimal? PackagingTare { get; set; }
/// <summary>托盘重量(KG)</summary>
public decimal? PalletWeight { get; set; }
public decimal? RemainingWeight { get; set; }
public int? RemainingQuantity { get; set; }

View File

@@ -17,11 +17,15 @@ public class MesXslRawMaterialEntry
public string? ManufacturerMaterialName { get; set; }
public string? ShelfLife { get; set; }
public double? TotalWeight { get; set; }
public double? PalletTareTotal { get; set; }
// 总份数 / 每份总重 / 每份包数:与后端同步升级为字符串,
// 用于持久化「拆码明细」多行拼接(如 20/1/、100/200/)。
public string? TotalPortions { get; set; }
public string? PortionWeight { get; set; }
public string? PortionPackagingTare { get; set; }
public string? PortionPalletWeight { get; set; }
public string? PortionTareStrategyIds { get; set; }
public string? PortionPackages { get; set; }
// 拆码明细各行库位的拼接(以 / 分隔,末尾带 /,如 1F-A01/1F-A02/)。
// 与 WarehouseLocation基础资料整票级单值独立专供明细行回填。

View File

@@ -0,0 +1,9 @@
namespace YY.Admin.Core.Entity;
public class MesXslUnit
{
public string? Id { get; set; }
public string? UnitCode { get; set; }
public string? UnitName { get; set; }
public int? TenantId { get; set; }
}

View File

@@ -40,6 +40,17 @@ public class MesXslWeightRecord
/// </summary>
public double? EnteredWeight { get; set; }
/// <summary>
/// 货物皮重(KG) —— 后端/本地实时计算,不入库。
/// 来源所有引用本榜单BillNo的原料入场记录 pallet_tare_total托盘及皮重合计累加。
/// </summary>
public double? CargoTareWeight { get; set; }
/// <summary>
/// 原料重量(KG) —— 实时计算,不入库。公式:净重 - 货物皮重。
/// </summary>
public double? RawMaterialWeight { get; set; }
/// <summary>司机姓名</summary>
public string? DriverName { get; set; }

View File

@@ -46,6 +46,8 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
new SysMenu{ Id=1300150010901, Pid=1300150000101, Title="原材料卡片", Path="/xslmes/mesXslRawMaterialCard", Name="mesXslRawMaterialCard", Component="RawMaterialCardListView", Icon="&#xe7ce;", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=108 },
// 库区管理
new SysMenu{ Id=1300150011001, Pid=1300150000101, Title="库区管理", Path="/xslmes/mesXslWarehouseArea", Name="mesXslWarehouseArea", Component="WarehouseAreaListView", Icon="&#xe7ce;", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=109 },
// 密炼物料皮重策略
new SysMenu{ Id=1300150011101, Pid=1300150000101, Title="密炼物料皮重策略", Path="/xslmes/mesXslMixerMaterialTareStrategy", Name="mesXslMixerMaterialTareStrategy", Component="MixerMaterialTareStrategyListView", Icon="&#xe7ce;", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 },
#endregion

View File

@@ -31,6 +31,7 @@ public class SysTenantMenuSeedData : ISqlSugarEntitySeedData<SysTenantMenu>
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010801},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010901},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011001},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011101},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012101},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012111},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012121},

View File

@@ -268,6 +268,8 @@ namespace YY.Admin.Core.SqlSugar
if (config.SeedSettings.EnableInitSeed) InitSeedData(db, config);
// 关闭全量种子时首启可能无菜单数据;补一份基准菜单,避免打包版本左侧空白
EnsureBaselineSysMenuSeed(db, config);
// 旧库升级:按种子补全缺失菜单及租户/角色授权(仅插入缺失项)
EnsureIncrementalDesktopMenuSeed(db, config);
}
/// <summary>
@@ -392,6 +394,106 @@ namespace YY.Admin.Core.SqlSugar
}
}
/// <summary>
/// 旧库升级sys_menu 已有数据时,按 SysMenuSeedData 补全缺失菜单,并同步租户菜单、管理员角色菜单授权。
/// </summary>
private static void EnsureIncrementalDesktopMenuSeed(SqlSugarScope db, DbConnectionConfig config)
{
try
{
if (!string.Equals(config.ConfigId.ToString(), SqlSugarConst.MainConfigId, StringComparison.Ordinal))
{
return;
}
if (config.DbType != DbType.Sqlite)
{
return;
}
var dbProvider = db.GetConnectionScope(config.ConfigId);
var menuEntityInfo = dbProvider.EntityMaintenance.GetEntityInfo(typeof(SysMenu));
if (!dbProvider.DbMaintenance.IsAnyTable(menuEntityInfo.DbTableName, false))
{
return;
}
if (dbProvider.Queryable<SysMenu>().ClearFilter().Count() == 0)
{
return;
}
var seedMenus = new SysMenuSeedData().HasData().ToList();
var existingMenuIds = dbProvider.Queryable<SysMenu>().ClearFilter()
.Select(m => m.Id).ToList().ToHashSet();
var missingMenus = seedMenus.Where(m => !existingMenuIds.Contains(m.Id)).ToList();
if (missingMenus.Count == 0)
{
return;
}
foreach (var menu in missingMenus)
{
if (menu.CreateTime == default)
{
menu.CreateTime = DateTime.Parse("2022-02-10 00:00:00");
}
menu.Status = StatusEnum.Enable;
}
dbProvider.Insertable(missingMenus).ExecuteCommand();
const long defaultTenantId = 1300000000001;
var tenantSeed = new SysTenantMenuSeedData().HasData()
.Where(t => t.TenantId == defaultTenantId)
.ToList();
var existingTenantMenuIds = dbProvider.Queryable<SysTenantMenu>()
.Where(t => t.TenantId == defaultTenantId)
.Select(t => t.MenuId)
.ToList()
.ToHashSet();
var tenantMenusToInsert = tenantSeed
.Where(t => missingMenus.Any(m => m.Id == t.MenuId) && !existingTenantMenuIds.Contains(t.MenuId))
.Select(t => new SysTenantMenu { Id = t.MenuId, TenantId = t.TenantId, MenuId = t.MenuId })
.ToList();
if (tenantMenusToInsert.Count > 0)
{
dbProvider.Insertable(tenantMenusToInsert).ExecuteCommand();
}
var adminRole = dbProvider.Queryable<SysRole>().OrderBy(r => r.Id).First();
if (adminRole == null)
{
return;
}
var existingRoleMenuIds = dbProvider.Queryable<SysRoleMenu>()
.Where(r => r.RoleId == adminRole.Id)
.Select(r => r.MenuId)
.ToList()
.ToHashSet();
var roleMenusToInsert = missingMenus
.Where(m => !existingRoleMenuIds.Contains(m.Id))
.Select(m => new SysRoleMenu
{
Id = m.Id + (adminRole.Id % 1300000000000),
RoleId = adminRole.Id,
MenuId = m.Id,
})
.ToList();
if (roleMenusToInsert.Count > 0)
{
dbProvider.Insertable(roleMenusToInsert).ExecuteCommand();
}
}
catch
{
// 启动阶段不因增量菜单失败而阻断
}
}
/// <summary>
/// 兼容旧库:补齐桌面端「登录设置」所需的 sys_config 配置项(升级前库可能缺少这些 code
/// </summary>

View File

@@ -0,0 +1,49 @@
using YY.Admin.Core.Entity;
namespace YY.Admin.Core.Util;
/// <summary>
/// 「货物皮重」桌面端本地累计计算器。
/// 与后端 IMesXslRawMaterialEntryService.sumCargoTareByBillNos 保持同一口径:
/// 同一榜单BillNo下所有原料入场记录的 PalletTareTotal托盘及皮重合计累加。
/// </summary>
public static class CargoTareWeightCalculator
{
/// <summary>按 BillNo 分组累计「货物皮重」。</summary>
public static Dictionary<string, double> SumByBillNos(
IEnumerable<MesXslRawMaterialEntry> entries,
IEnumerable<string?> billNos)
{
var keys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var b in billNos)
{
if (!string.IsNullOrWhiteSpace(b)) keys.Add(b!);
}
var result = new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase);
if (keys.Count == 0)
{
return result;
}
foreach (var e in entries)
{
if (string.IsNullOrWhiteSpace(e.BillNo) || !keys.Contains(e.BillNo!))
{
continue;
}
if (e.PalletTareTotal is not { } tare || tare == 0d)
{
continue;
}
if (result.TryGetValue(e.BillNo!, out var acc))
{
result[e.BillNo!] = acc + tare;
}
else
{
result[e.BillNo!] = tare;
}
}
return result;
}
}