From c54d54b40f2e252b7891db3ff84f91f79cac6485 Mon Sep 17 00:00:00 2001 From: jiangxh <1217934998@qq.com> Date: Thu, 18 Jun 2026 15:18:11 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A1=8C=E9=9D=A2=E7=AB=AF=E5=AF=86=E7=82=BC?= =?UTF-8?q?=E8=AE=A1=E5=88=92=E3=80=81=E8=83=B6=E6=96=99=E5=BF=AB=E6=A3=80?= =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MesXslDesktopAnonController.java | 28 +- .../entity/MesXslRubberQuickTestStd.java | 8 + .../IMesXslRubberQuickTestRecordService.java | 8 + ...esXslRubberQuickTestRecordServiceImpl.java | 60 + .../IRubberQuickTestOperationService.cs | 6 +- .../Services/IRubberQuickTestStdService.cs | 7 + .../Entity/MesXslMixingProductionPlan.cs | 14 + .../Entity/MesXslRubberQuickTestStd.cs | 3 + .../YY.Admin.Core/SeedData/SysMenuSeedData.cs | 6 +- .../YY.Admin.Core/SqlSugar/SqlSugarSetup.cs | 39 + .../RubberQuickTestOperationService.cs | 53 +- .../RubberQuickTestStdService.cs | 38 + .../YY.Admin/Module/NavigationExtensions.cs | 2 +- .../ViewModels/Control/MenuTreeViewModel.cs | 2 +- .../RubberQuickTestOperationViewModel.cs | 1241 ++++++++++++++--- .../MixingProductionPlanListView.xaml | 14 +- .../RubberQuickTestOperationView.xaml | 117 +- .../RubberQuickTestOperationView.xaml.cs | 162 ++- .../RubberQuickTestStdDetailDialogView.xaml | 5 + .../RubberQuickTestStdListView.xaml | 7 +- 20 files changed, 1509 insertions(+), 311 deletions(-) diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDesktopAnonController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDesktopAnonController.java index 0937563b..9405a62a 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDesktopAnonController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDesktopAnonController.java @@ -35,6 +35,7 @@ import org.jeecg.modules.xslmes.entity.MesXslVehicle; import org.jeecg.modules.xslmes.entity.MesXslWarehouse; import org.jeecg.modules.xslmes.entity.MesXslWarehouseArea; import org.jeecg.modules.xslmes.entity.MesXslMixingProductionPlan; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestMethod; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd; @@ -50,6 +51,7 @@ import org.jeecg.modules.xslmes.service.IMesXslVehicleService; import org.jeecg.modules.xslmes.service.IMesXslWarehouseAreaService; import org.jeecg.modules.xslmes.service.IMesXslWarehouseService; import org.jeecg.modules.xslmes.service.IMesXslMixingProductionPlanService; +import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService; import org.jeecg.modules.xslmes.service.IMesXslWeightRecordService; @@ -100,6 +102,7 @@ public class MesXslDesktopAnonController { private final IMesXslMixingProductionPlanService mixingProductionPlanService; private final IMesXslRubberQuickTestStdService rubberQuickTestStdService; private final IMesXslRubberQuickTestRecordService rubberQuickTestRecordService; + private final IMesXslRubberQuickTestMethodService rubberQuickTestMethodService; // ═══════════════════════════ 车辆管理 ═══════════════════════════ @@ -965,6 +968,9 @@ public class MesXslDesktopAnonController { QueryWrapper qw = QueryGenerator.initQueryWrapper(model, req.getParameterMap()); qw.orderByDesc("create_time"); IPage page = rubberQuickTestStdService.page(new Page<>(pageNo, pageSize), qw); + if (page.getRecords() != null) { + page.getRecords().forEach(this::fillStdQuickTestTypeFromMethod); + } return Result.OK(page); } @@ -976,6 +982,7 @@ public class MesXslDesktopAnonController { return Result.error("未找到对应数据"); } entity.setLineList(rubberQuickTestStdService.selectLinesByStdId(id)); + fillStdQuickTestTypeFromMethod(entity); return Result.OK(entity); } //update-end---author:jiangxh ---date:2026-06-17 for:【快检实验标准】桌面端只读列表与详情----------- @@ -1001,6 +1008,7 @@ public class MesXslDesktopAnonController { return Result.error("未找到胶料「" + name + "」对应的使用中且已批准的快检实验标准"); } std.setLineList(rubberQuickTestStdService.selectLinesByStdId(std.getId())); + fillStdQuickTestTypeFromMethod(std); return Result.OK(std); } @@ -1027,9 +1035,13 @@ public class MesXslDesktopAnonController { return Result.error("请维护检验明细"); } try { + if (oConvertUtils.isEmpty(record.getRecordNo())) { + record.setRecordNo(rubberQuickTestRecordService.generateDesktopRecordNo(record)); + } + rubberQuickTestRecordService.fillQuickTestTypeForRecord(record); rubberQuickTestRecordService.saveMain(record, lineList); stompNotify.publishRubberQuickTestRecordChanged("add", record.getId()); - return Result.OK("添加成功!"); + return Result.OK(record.getRecordNo()); } catch (Exception e) { log.error(e.getMessage(), e); return Result.error(e.getMessage()); @@ -1037,6 +1049,20 @@ public class MesXslDesktopAnonController { } //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】桌面端胶料快检记录保存----------- + //update-begin---author:jiangxh ---date:20260618 for:【快检实验标准】桌面端回填实验方法关联实验类型----------- + private void fillStdQuickTestTypeFromMethod(MesXslRubberQuickTestStd std) { + if (std == null || oConvertUtils.isEmpty(std.getTestMethodId())) { + return; + } + MesXslRubberQuickTestMethod method = rubberQuickTestMethodService.getById(std.getTestMethodId()); + if (method == null) { + return; + } + std.setQuickTestTypeId(method.getQuickTestTypeId()); + std.setQuickTestTypeName(method.getQuickTestTypeName()); + } + //update-end---author:jiangxh ---date:20260618 for:【快检实验标准】桌面端回填实验方法关联实验类型----------- + // ─────────────────────────── 车辆私有辅助 ──────────────────────────── private void applyWeightNetAndBillType(MesXslWeightRecord record) { diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestStd.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestStd.java index 743b95fa..6c738981 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestStd.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestStd.java @@ -106,4 +106,12 @@ public class MesXslRubberQuickTestStd implements Serializable { @TableField(exist = false) @Schema(description = "标准明细") private List lineList; + + @TableField(exist = false) + @Schema(description = "实验类型ID(来自实验方法,桌面端展示)") + private String quickTestTypeId; + + @TableField(exist = false) + @Schema(description = "实验类型名称(来自实验方法,桌面端展示)") + private String quickTestTypeName; } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslRubberQuickTestRecordService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslRubberQuickTestRecordService.java index 8c5a0858..4801b300 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslRubberQuickTestRecordService.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslRubberQuickTestRecordService.java @@ -25,5 +25,13 @@ public interface IMesXslRubberQuickTestRecordService extends IService batchFromMaterial(MesXslRubberQuickTestRecordBatchFromMaterialVO vo); } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestRecordServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestRecordServiceImpl.java index c20d1797..a40639f3 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestRecordServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestRecordServiceImpl.java @@ -216,6 +216,66 @@ public class MesXslRubberQuickTestRecordServiceImpl } //update-end---author:jiangxh ---date:20260528 for:【MES】胶料快检记录单号JL+日期+4位流水自动生成----------- + //update-begin---author:jiangxh ---date:20260618 for:【快检记录】桌面端快检记录号 yyyyMMdd+流水+胶料号----------- + @Override + public String generateDesktopRecordNo(MesXslRubberQuickTestRecord context) { + String dateStr = new SimpleDateFormat("yyyyMMdd").format(new Date()); + if (context == null || oConvertUtils.isEmpty(context.getRubberMaterialName())) { + throw new JeecgBootException("胶料名称不能为空,无法生成快检记录号"); + } + String material = context.getRubberMaterialName().trim(); + int expectedLen = dateStr.length() + 4 + material.length(); + Integer tenantId = resolveTenantId(context); + + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.likeRight(MesXslRubberQuickTestRecord::getRecordNo, dateStr); + qw.and(q -> q.eq(MesXslRubberQuickTestRecord::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesXslRubberQuickTestRecord::getDelFlag)); + if (tenantId != null) { + qw.eq(MesXslRubberQuickTestRecord::getTenantId, tenantId); + } + qw.select(MesXslRubberQuickTestRecord::getRecordNo); + + int maxSeq = 0; + for (MesXslRubberQuickTestRecord row : this.list(qw)) { + String no = row.getRecordNo(); + if (oConvertUtils.isEmpty(no) || no.length() != expectedLen) { + continue; + } + if (!no.startsWith(dateStr) || !no.endsWith(material)) { + continue; + } + String seqPart = no.substring(dateStr.length(), dateStr.length() + 4); + try { + maxSeq = Math.max(maxSeq, Integer.parseInt(seqPart)); + } catch (NumberFormatException ignored) { + // ignore malformed historical numbers + } + } + return dateStr + String.format("%04d", maxSeq + 1) + material; + } + + @Override + public void fillQuickTestTypeForRecord(MesXslRubberQuickTestRecord record) { + if (record == null || oConvertUtils.isNotEmpty(record.getQuickTestTypeId())) { + return; + } + String testMethodId = null; + if (oConvertUtils.isNotEmpty(record.getStdId())) { + MesXslRubberQuickTestStd std = mesXslRubberQuickTestStdService.getById(record.getStdId()); + if (std != null) { + testMethodId = std.getTestMethodId(); + } + } + if (oConvertUtils.isEmpty(testMethodId)) { + return; + } + MesXslRubberQuickTestMethod method = mesXslRubberQuickTestMethodService.getById(testMethodId); + if (method != null && oConvertUtils.isNotEmpty(method.getQuickTestTypeId())) { + fillQuickTestType(record, method.getQuickTestTypeId()); + } + } + //update-end---author:jiangxh ---date:20260618 for:【快检记录】桌面端快检记录号 yyyyMMdd+流水+胶料号----------- + //update-begin---author:jiangxh ---date:20260525 for:【MES】胶料信息多选按实验标准批量生成快检记录----------- @Override @Transactional(rollbackFor = Exception.class) diff --git a/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestOperationService.cs b/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestOperationService.cs index 24d82053..8fd8232c 100644 --- a/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestOperationService.cs +++ b/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestOperationService.cs @@ -2,12 +2,8 @@ using YY.Admin.Core.Entity; namespace YY.Admin.Core.Services; -/// 胶料快检记录操作台:密炼计划筛选、实验标准匹配、记录保存 +/// 胶料快检记录操作台:保存至 MES public interface IRubberQuickTestOperationService { - Task> GetMixingProductionPlansAsync(CancellationToken ct = default); - - Task GetStdByRubberMaterialNameAsync(string rubberMaterialName, CancellationToken ct = default); - Task SaveRecordAsync(MesXslRubberQuickTestRecord record, CancellationToken ct = default); } diff --git a/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestStdService.cs b/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestStdService.cs index da3ba174..9535081a 100644 --- a/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestStdService.cs +++ b/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestStdService.cs @@ -14,6 +14,13 @@ public interface IRubberQuickTestStdService Task GetByIdAsync(string id, CancellationToken ct = default); + Task> GetAllCachedAsync(CancellationToken ct = default); + + Task GetCachedByIdAsync(string id, CancellationToken ct = default); + + /// 优先读本地缓存;无明细时联网拉取详情并回写缓存 + Task GetWithLinesAsync(string id, CancellationToken ct = default); + /// 本地缓存是否有变更(有差异才写入) Task SyncFromRemoteAsync(CancellationToken ct = default); } diff --git a/yy-admin-master/YY.Admin.Core/Entity/MesXslMixingProductionPlan.cs b/yy-admin-master/YY.Admin.Core/Entity/MesXslMixingProductionPlan.cs index 2ff7dffd..f91f67f5 100644 --- a/yy-admin-master/YY.Admin.Core/Entity/MesXslMixingProductionPlan.cs +++ b/yy-admin-master/YY.Admin.Core/Entity/MesXslMixingProductionPlan.cs @@ -47,4 +47,18 @@ public class MesXslMixingProductionPlan }; public string PlanDateText => PlanDate?.ToString("yyyy-MM-dd") ?? string.Empty; + + /// 计划+胶料号:计划号_胶料名称,如 SA0001_HB10001 + public string PlanMaterialNo + { + get + { + var planNo = PlanNo?.Trim(); + var materialName = MaterialName?.Trim(); + if (string.IsNullOrEmpty(planNo) && string.IsNullOrEmpty(materialName)) return string.Empty; + if (string.IsNullOrEmpty(planNo)) return materialName ?? string.Empty; + if (string.IsNullOrEmpty(materialName)) return planNo; + return $"{planNo}_{materialName}"; + } + } } diff --git a/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStd.cs b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStd.cs index 7b4d775b..109f489d 100644 --- a/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStd.cs +++ b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStd.cs @@ -9,6 +9,9 @@ public class MesXslRubberQuickTestStd public string? StdName { get; set; } public string? TestMethodId { get; set; } public string? TestMethodName { get; set; } + /// 实验类型(来自实验方法,MES 回填) + public string? QuickTestTypeId { get; set; } + public string? QuickTestTypeName { get; set; } public string? MixerType { get; set; } public string? RubberMaterialId { get; set; } public string? RubberMaterialName { get; set; } diff --git a/yy-admin-master/YY.Admin.Core/SeedData/SysMenuSeedData.cs b/yy-admin-master/YY.Admin.Core/SeedData/SysMenuSeedData.cs index 86d6061a..95fd7f1c 100644 --- a/yy-admin-master/YY.Admin.Core/SeedData/SysMenuSeedData.cs +++ b/yy-admin-master/YY.Admin.Core/SeedData/SysMenuSeedData.cs @@ -48,12 +48,12 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData new SysMenu{ Id=1300150011001, Pid=1300150000101, Title="库区管理", Path="/xslmes/mesXslWarehouseArea", Name="mesXslWarehouseArea", Component="WarehouseAreaListView", Icon="", 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="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 }, - // 快检记录 - new SysMenu{ Id=1300150011201, Pid=1300150000101, Title="快检记录", Path="/xslmes/rubberQuickTestOperation", Name="rubberQuickTestOperation", Component="RubberQuickTestOperationView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=111 }, // 胶料快检实验标准(桌面端只读) new SysMenu{ Id=1300150011301, Pid=1300150000101, Title="胶料快检实验标准", Path="/xslmes/mesXslRubberQuickTestStd", Name="mesXslRubberQuickTestStd", Component="RubberQuickTestStdListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=112 }, + // 胶料快检记录(紧接实验标准之后) + new SysMenu{ Id=1300150011201, Pid=1300150000101, Title="胶料快检记录", Path="/xslmes/rubberQuickTestOperation", Name="rubberQuickTestOperation", Component="RubberQuickTestOperationView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=113 }, // 密炼计划 - new SysMenu{ Id=1300150011401, Pid=1300150000101, Title="密炼计划", Path="/xslmes/mesXslMixingProductionPlan", Name="mesXslMixingProductionPlan", Component="MixingProductionPlanListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=113 }, + new SysMenu{ Id=1300150011401, Pid=1300150000101, Title="密炼计划", Path="/xslmes/mesXslMixingProductionPlan", Name="mesXslMixingProductionPlan", Component="MixingProductionPlanListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=114 }, #endregion diff --git a/yy-admin-master/YY.Admin.Core/SqlSugar/SqlSugarSetup.cs b/yy-admin-master/YY.Admin.Core/SqlSugar/SqlSugarSetup.cs index f990bb40..14ea2257 100644 --- a/yy-admin-master/YY.Admin.Core/SqlSugar/SqlSugarSetup.cs +++ b/yy-admin-master/YY.Admin.Core/SqlSugar/SqlSugarSetup.cs @@ -270,6 +270,8 @@ namespace YY.Admin.Core.SqlSugar EnsureBaselineSysMenuSeed(db, config); // 旧库升级:按种子补全缺失菜单及租户/角色授权(仅插入缺失项) EnsureIncrementalDesktopMenuSeed(db, config); + // 旧库升级:胶料快检记录菜单名称与排序 + EnsureRubberQuickTestRecordMenuPatch(db, config); } /// @@ -494,6 +496,43 @@ namespace YY.Admin.Core.SqlSugar } } + /// + /// 旧库升级:胶料快检记录改名为「胶料快检记录」,排序置于胶料快检实验标准之后。 + /// + private static void EnsureRubberQuickTestRecordMenuPatch(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; + + const long quickTestRecordMenuId = 1300150011201; + const long mixingPlanMenuId = 1300150011401; + + dbProvider.Updateable() + .SetColumns(m => m.Title == "胶料快检记录") + .SetColumns(m => m.OrderNo == 113) + .Where(m => m.Id == quickTestRecordMenuId) + .ExecuteCommand(); + + dbProvider.Updateable() + .SetColumns(m => m.OrderNo == 114) + .Where(m => m.Id == mixingPlanMenuId) + .ExecuteCommand(); + } + catch + { + // 启动阶段不因菜单补丁失败而阻断 + } + } + /// /// 兼容旧库:补齐桌面端「登录设置」所需的 sys_config 配置项(升级前库可能缺少这些 code) /// diff --git a/yy-admin-master/YY.Admin.Services/Service/RubberQuickTest/RubberQuickTestOperationService.cs b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTest/RubberQuickTestOperationService.cs index e0484ac6..f603e985 100644 --- a/yy-admin-master/YY.Admin.Services/Service/RubberQuickTest/RubberQuickTestOperationService.cs +++ b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTest/RubberQuickTestOperationService.cs @@ -14,7 +14,6 @@ public class RubberQuickTestOperationService : IRubberQuickTestOperationService, private readonly IHttpClientFactory _httpClientFactory; private readonly IConfiguration _configuration; private readonly INetworkMonitor _networkMonitor; - private readonly IMixingProductionPlanService _mixingProductionPlanService; private readonly ILoggerService _logger; private static readonly JsonSerializerOptions _jsonOpts = new() @@ -28,54 +27,20 @@ public class RubberQuickTestOperationService : IRubberQuickTestOperationService, IHttpClientFactory httpClientFactory, IConfiguration configuration, INetworkMonitor networkMonitor, - IMixingProductionPlanService mixingProductionPlanService, ILoggerService logger) { _httpClientFactory = httpClientFactory; _configuration = configuration; _networkMonitor = networkMonitor; - _mixingProductionPlanService = mixingProductionPlanService; _logger = logger; } private string BaseUrl => (_configuration.GetValue("JeecgIntegration:BaseUrl") ?? "http://localhost:8080/jeecg-boot").TrimEnd('/'); - private int DefaultTenantId => (int?)_configuration.GetValue("JeecgIntegration:DefaultTenantId") ?? 1002; - - public async Task> GetMixingProductionPlansAsync(CancellationToken ct = default) - { - var result = await _mixingProductionPlanService.GetAllCachedAsync(ct).ConfigureAwait(false); - _logger.Information($"[快检记录] 加载密炼生产计划 {result.Count} 条"); - return result; - } - - public async Task GetStdByRubberMaterialNameAsync(string rubberMaterialName, CancellationToken ct = default) - { - if (string.IsNullOrWhiteSpace(rubberMaterialName)) - return null; - if (!_networkMonitor.IsOnline) - throw new InvalidOperationException("网络未连接,无法加载实验标准"); - - var encoded = Uri.EscapeDataString(rubberMaterialName.Trim()); - var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestStd/anon/queryByRubberMaterialName?rubberMaterialName={encoded}"; - using var client = _httpClientFactory.CreateClient("JeecgApi"); - var resp = await client.GetAsync(url, ct).ConfigureAwait(false); - var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false); - using var doc = JsonDocument.Parse(json); - if (!doc.RootElement.TryGetProperty("success", out var successEl) || !successEl.GetBoolean()) - { - var msg = doc.RootElement.TryGetProperty("message", out var msgEl) ? msgEl.GetString() : "查询实验标准失败"; - _logger.Warning($"[快检记录] 实验标准查询失败: {msg}"); - return null; - } - if (!doc.RootElement.TryGetProperty("result", out var resultEl) || resultEl.ValueKind == JsonValueKind.Null) - return null; - return resultEl.Deserialize(_jsonOpts); - } public async Task SaveRecordAsync(MesXslRubberQuickTestRecord record, CancellationToken ct = default) { if (!_networkMonitor.IsOnline) - throw new InvalidOperationException("网络未连接,无法保存快检记录"); + throw new InvalidOperationException("网络未连接,无法保存胶料快检记录"); var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestRecord/anon/add"; using var client = _httpClientFactory.CreateClient("JeecgApi"); @@ -89,7 +54,19 @@ public class RubberQuickTestOperationService : IRubberQuickTestOperationService, var msg = doc.RootElement.TryGetProperty("message", out var msgEl) ? msgEl.GetString() : "保存失败"; throw new InvalidOperationException(msg ?? "保存失败"); } - _logger.Information($"[快检记录] 保存成功 recordNo={record.RecordNo}"); - return doc.RootElement.TryGetProperty("message", out var m) ? m.GetString() : "保存成功"; + + string? recordNo = null; + if (doc.RootElement.TryGetProperty("result", out var resultEl)) + { + if (resultEl.ValueKind == JsonValueKind.String) + recordNo = resultEl.GetString(); + else if (resultEl.ValueKind == JsonValueKind.Object + && resultEl.TryGetProperty("recordNo", out var noEl)) + recordNo = noEl.GetString(); + } + recordNo ??= record.RecordNo; + record.RecordNo = recordNo; + _logger.Information($"[胶料快检记录] 保存成功 recordNo={recordNo}"); + return recordNo; } } diff --git a/yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdService.cs b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdService.cs index 628b8b65..a2cdbf11 100644 --- a/yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdService.cs +++ b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdService.cs @@ -135,6 +135,42 @@ public class RubberQuickTestStdService : IRubberQuickTestStdService, ISingletonD } } + public Task> GetAllCachedAsync(CancellationToken ct = default) + { + ct.ThrowIfCancellationRequested(); + lock (_cacheLock) + return Task.FromResult(_localCache.Select(CloneMain).ToList()); + } + + public Task GetCachedByIdAsync(string id, CancellationToken ct = default) + { + ct.ThrowIfCancellationRequested(); + if (string.IsNullOrWhiteSpace(id)) return Task.FromResult(null); + lock (_cacheLock) + { + var found = _localCache.FirstOrDefault(x => string.Equals(x.Id, id, StringComparison.OrdinalIgnoreCase)); + return Task.FromResult(found != null ? CloneMain(found) : null); + } + } + + public async Task GetWithLinesAsync(string id, CancellationToken ct = default) + { + if (string.IsNullOrWhiteSpace(id)) return null; + + var cached = await GetCachedByIdAsync(id, ct).ConfigureAwait(false); + if (cached?.LineList is { Count: > 0 }) + return cached; + + if (_networkMonitor.IsOnline) + { + var detail = await GetByIdAsync(id, ct).ConfigureAwait(false); + if (detail != null) + return detail; + } + + return cached; + } + public async Task SyncFromRemoteAsync(CancellationToken ct = default) { await _syncLock.WaitAsync(ct).ConfigureAwait(false); @@ -309,6 +345,8 @@ public class RubberQuickTestStdService : IRubberQuickTestStdService, ISingletonD StdName = x.StdName, TestMethodId = x.TestMethodId, TestMethodName = x.TestMethodName, + QuickTestTypeId = x.QuickTestTypeId, + QuickTestTypeName = x.QuickTestTypeName, MixerType = x.MixerType, RubberMaterialId = x.RubberMaterialId, RubberMaterialName = x.RubberMaterialName, diff --git a/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs b/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs index e7e92f9e..08597703 100644 --- a/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs +++ b/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs @@ -98,7 +98,7 @@ namespace YY.Admin containerRegistry.RegisterForNavigation(); // 密炼物料皮重策略 containerRegistry.RegisterForNavigation(); - // 快检记录操作台 + // 胶料快检记录操作台 containerRegistry.RegisterForNavigation(); // 胶料快检实验标准(只读) containerRegistry.RegisterForNavigation(); diff --git a/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs index 256ee8ee..bdd42ea5 100644 --- a/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs +++ b/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs @@ -152,7 +152,7 @@ namespace YY.Admin.ViewModels.Control ["/xslmes/mesXslMixerMaterialTareStrategy"] = "MixerMaterialTareStrategyListView", ["mesXslMixerMaterialTareStrategy"] = "MixerMaterialTareStrategyListView", - // 已实现页面:快检记录操作台 + // 已实现页面:胶料快检记录操作台 ["RubberQuickTestOperationView"] = "RubberQuickTestOperationView", ["/xslmes/rubberQuickTestOperation"] = "RubberQuickTestOperationView", ["rubberQuickTestOperation"] = "RubberQuickTestOperationView", diff --git a/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs index 095d81c6..049795ac 100644 --- a/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs +++ b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs @@ -1,426 +1,995 @@ using HandyControl.Controls; + using LiveChartsCore; +using LiveChartsCore.Defaults; using LiveChartsCore.SkiaSharpView; + using LiveChartsCore.SkiaSharpView.Painting; + +using Prism.Events; + using Prism.Mvvm; + using SkiaSharp; + using System.Collections.ObjectModel; + using YY.Admin.Core; + using YY.Admin.Core.Entity; + +using YY.Admin.Core.Events; + using YY.Admin.Core.Services; + using YY.Admin.Core.Session; + + namespace YY.Admin.ViewModels.RubberQuickTest; -/// 密炼生产计划班次展开项(桌面端筛选用) -public class MixingPlanShiftOption -{ - public string PlanRowId { get; set; } = string.Empty; - public string? MachineId { get; set; } - public string? MachineName { get; set; } - public string ShiftKey { get; set; } = string.Empty; - public string ShiftCode { get; set; } = string.Empty; - public string ShiftName { get; set; } = string.Empty; - public DateTime? OrderDate { get; set; } - public string? PlanId { get; set; } - public string? OrderNo { get; set; } - public string? FormulaName { get; set; } - public string? MaterialName { get; set; } - public string DisplayText => string.IsNullOrWhiteSpace(OrderNo) - ? MaterialName ?? FormulaName ?? string.Empty - : $"{OrderNo} | {MaterialName ?? FormulaName}"; -} + public class QuickTestInspectCellViewModel : BindableBase + { + public string? DataPointId { get; set; } + public string PointName { get; set; } = string.Empty; + public decimal? LowerLimit { get; set; } + public decimal? UpperLimit { get; set; } + + private decimal? _value; + public decimal? Value + { + get => _value; + set + { + if (SetProperty(ref _value, value)) + ValueChanged?.Invoke(this); + } + } + + public event Action? ValueChanged; + } + + public class QuickTestInspectRowViewModel : BindableBase { - public string RowNo { get; set; } = string.Empty; + private string _rowNo = string.Empty; + public string RowNo + { + get => _rowNo; + set => SetProperty(ref _rowNo, value); + } + public ObservableCollection Cells { get; } = new(); + + private string _inspectResultText = string.Empty; + public string InspectResultText + { + get => _inspectResultText; + set => SetProperty(ref _inspectResultText, value); + } + + public string InspectResultCode { get; private set; } = "0"; + + public void RecalculateResult() + { + if (Cells.Count == 0) + { + InspectResultCode = "0"; + InspectResultText = string.Empty; + RaisePropertyChanged(nameof(InspectResultText)); + return; + } + + if (Cells.Any(c => c.Value == null)) + { + InspectResultCode = "0"; + InspectResultText = "待填写"; + RaisePropertyChanged(nameof(InspectResultText)); + return; + } + + var pass = Cells.All(c => + { + if (c.LowerLimit != null && c.Value < c.LowerLimit) return false; + if (c.UpperLimit != null && c.Value > c.UpperLimit) return false; + return true; + }); + InspectResultCode = pass ? "1" : "0"; + InspectResultText = pass ? "合格" : "不合格"; + RaisePropertyChanged(nameof(InspectResultText)); + } + } -/// 胶料快检记录操作台 ViewModel + + +/// 胶料快检记录操作台 ViewModel(密炼计划、实验标准均读本地缓存) + public class RubberQuickTestOperationViewModel : BaseViewModel + { + private readonly IRubberQuickTestOperationService _operationService; + + private readonly IMixingProductionPlanService _planService; + + private readonly IRubberQuickTestStdService _stdService; + private readonly Random _rnd = new(); + private List _allPlans = new(); - private List _allShiftOptions = new(); + + private List _allStds = new(); + private MesXslRubberQuickTestStd? _currentStd; + + private SubscriptionToken? _planChangedToken; + + private SubscriptionToken? _stdChangedToken; + private const int ChartPointCount = 5; + /// 曲线横坐标时间点(min):0、0.5、1、1.5、2 + private static readonly double[] ChartTimeMinutes = { 0, 0.5, 1, 1.5, 2 }; + + + public event Action? InspectColumnsChanged; + + public RubberQuickTestOperationViewModel( + IRubberQuickTestOperationService operationService, + + IMixingProductionPlanService planService, + + IRubberQuickTestStdService stdService, + IContainerExtension container, + IRegionManager regionManager) : base(container, regionManager) + { + _operationService = operationService; + _planService = planService; + + _stdService = stdService; + + + _inspectTimesText = "1"; + + AddInspectRowCommand = new DelegateCommand(AddInspectRow, () => DataPointColumns.Count > 0); + RemoveInspectRowCommand = new DelegateCommand(() => RemoveInspectRow(SelectedInspectRow), () => SelectedInspectRow != null); + SaveCommand = new DelegateCommand(async () => await SaveAsync(), () => InspectRows.Count > 0); - RefreshPlansCommand = new DelegateCommand(async () => await LoadPlansAsync()); + + RefreshPlansCommand = new DelegateCommand(async () => await LoadLocalDataAsync(showSuccess: true)); + RefreshChartDemoCommand = new DelegateCommand(FillRandomChartData); + + TemperatureSeries = new ObservableCollection { - new LineSeries { Name = "上模温度", Values = UpperTempValues, GeometrySize = 4, LineSmoothness = 0.3 }, - new LineSeries { Name = "下模温度", Values = LowerTempValues, GeometrySize = 4, LineSmoothness = 0.3 } + new LineSeries { Name = "上模温度", Values = UpperTempValues, GeometrySize = 4, LineSmoothness = 0.3 }, + new LineSeries { Name = "下模温度", Values = LowerTempValues, GeometrySize = 4, LineSmoothness = 0.3 } }; TorqueSeries = new ObservableCollection { - new LineSeries { Name = "S'(dNm)", Values = TorqueValues, GeometrySize = 4, LineSmoothness = 0.3 } + new LineSeries { Name = "S'(dNm)", Values = TorqueValues, GeometrySize = 4, LineSmoothness = 0.3 } }; + + FillRandomChartData(); - _ = LoadPlansAsync(); + + InspectorDisplay = ResolveInspectorDisplay(); + + + + _planChangedToken = _eventAggregator.GetEvent() + .Subscribe(async _ => await ReloadLocalDataQuietAsync(), ThreadOption.UIThread); + _stdChangedToken = _eventAggregator.GetEvent() + .Subscribe(async _ => await ReloadLocalDataQuietAsync(), ThreadOption.UIThread); + + + + _ = LoadLocalDataAsync(showSuccess: false); + + RecalculateOverallInspectResult(); } + + + private static string ResolveInspectorDisplay() + + { + + var user = AppSession.CurrentUser; + + if (user == null) return string.Empty; + + if (!string.IsNullOrWhiteSpace(user.RealName)) return user.RealName.Trim(); + + if (!string.IsNullOrWhiteSpace(user.Account)) return user.Account.Trim(); + + return string.Empty; + + } + + + /// 中间库未接入时的曲线演示说明 + public string ChartDemoHint => "演示数据(中间库未接入,打开页面自动生成;接入后将显示实测曲线)"; + + public ObservableCollection TemperatureSeries { get; } + public ObservableCollection TorqueSeries { get; } - public ObservableCollection UpperTempValues { get; } = new(); - public ObservableCollection LowerTempValues { get; } = new(); - public ObservableCollection TorqueValues { get; } = new(); + + public ObservableCollection UpperTempValues { get; } = new(); + public ObservableCollection LowerTempValues { get; } = new(); + public ObservableCollection TorqueValues { get; } = new(); + + public Axis[] TemperatureXAxes { get; } = BuildTimeAxis(); + public Axis[] TemperatureYAxes { get; } = BuildTempYAxis(); + public Axis[] TorqueXAxes { get; } = BuildTimeAxis(); + public Axis[] TorqueYAxes { get; } = BuildTorqueYAxis(); + + public ObservableCollection MachineOptions { get; } = new(); + public ObservableCollection ShiftOptions { get; } = new(); - public ObservableCollection PlanOptions { get; } = new(); + + public ObservableCollection PlanOptions { get; } = new(); + + public ObservableCollection StdOptions { get; } = new(); + public ObservableCollection DataPointColumns { get; } = new(); + public ObservableCollection InspectRows { get; } = new(); + + private QuickTestInspectRowViewModel? _selectedInspectRow; + public QuickTestInspectRowViewModel? SelectedInspectRow + { + get => _selectedInspectRow; + set + { + if (SetProperty(ref _selectedInspectRow, value)) + RemoveInspectRowCommand.RaiseCanExecuteChanged(); + } + } + + private DateTime _mixingDate = DateTime.Today; + public DateTime MixingDate + { + get => _mixingDate; + set + { + if (!SetProperty(ref _mixingDate, value)) return; + RefreshMachineOptions(); - ClearPlanSelection(); + + ClearPlanAndStdSelection(); + } + } + + private string? _selectedMachine; + public string? SelectedMachine + { + get => _selectedMachine; + set + { + if (!SetProperty(ref _selectedMachine, value)) return; + RefreshShiftOptions(); - ClearPlanSelection(); + + ClearPlanAndStdSelection(); + } + } + + private WorkShiftOption? _selectedShift; + public WorkShiftOption? SelectedShift + { + get => _selectedShift; + set + { + if (!SetProperty(ref _selectedShift, value)) return; + RefreshPlanOptions(); - ClearPlanSelection(); + + ClearPlanAndStdSelection(); + } + } - private MixingPlanShiftOption? _selectedPlan; - public MixingPlanShiftOption? SelectedPlan + + + private MesXslMixingProductionPlan? _selectedPlan; + + public MesXslMixingProductionPlan? SelectedPlan + { + get => _selectedPlan; + set + { + if (!SetProperty(ref _selectedPlan, value)) return; + ApplySelectedPlan(); + } + } - public string? ProductionOrderNo => _selectedPlan?.OrderNo; + + + private MesXslRubberQuickTestStd? _selectedStd; + + public MesXslRubberQuickTestStd? SelectedStd + + { + + get => _selectedStd; + + set + + { + + if (!SetProperty(ref _selectedStd, value)) return; + + _ = ApplySelectedStdAsync(); + + } + + } + + + public string? MachineName => _selectedPlan?.MachineName ?? SelectedMachine; + public string? WorkShiftDisplay => SelectedShift?.Name ?? string.Empty; + public string? RubberMaterialName => _selectedPlan?.MaterialName ?? _selectedPlan?.FormulaName; - private string? _trainNo; - public string? TrainNo + + + private string? _testMethodName; + + public string? TestMethodName + { - get => _trainNo; - set => SetProperty(ref _trainNo, value); + + get => _testMethodName; + + private set => SetProperty(ref _testMethodName, value); + } + + + private string? _trainNo; + + public string? TrainNo + + { + + get => _trainNo; + + set => SetProperty(ref _trainNo, value); + + } + + + + private string? _recordNo; + + /// 快检记录号(保存后由 MES 生成,只读) + + public string? RecordNo + + { + + get => _recordNo; + + private set => SetProperty(ref _recordNo, value); + + } + + + + private string _inspectorDisplay = string.Empty; + /// 检验人(当前登录用户,只读) + public string InspectorDisplay + { + get => _inspectorDisplay; + private set => SetProperty(ref _inspectorDisplay, value); + } + + private string _overallInspectResultDisplay = "不合格"; + /// 检验结果(试验信息区汇总,只读) + public string OverallInspectResultDisplay + { + get => _overallInspectResultDisplay; + private set => SetProperty(ref _overallInspectResultDisplay, value); + } + + /// 检验结果编码:1 合格,0 不合格 + public string OverallInspectResultCode { get; private set; } = "0"; + private string? _inspectTimesText; + /// 试验次数(手填正整数) + public string? InspectTimesText + { + get => _inspectTimesText; + set => SetProperty(ref _inspectTimesText, value); + } + + private double _upperMoldTemp; + public double UpperMoldTemp + { + get => _upperMoldTemp; + set => SetProperty(ref _upperMoldTemp, value); + } + + private double _lowerMoldTemp; + public double LowerMoldTemp + { + get => _lowerMoldTemp; + set => SetProperty(ref _lowerMoldTemp, value); + } + + private double _torqueS; + public double TorqueS + { + get => _torqueS; + set => SetProperty(ref _torqueS, value); + } + + public DelegateCommand AddInspectRowCommand { get; } + public DelegateCommand RemoveInspectRowCommand { get; } + public DelegateCommand SaveCommand { get; } + public DelegateCommand RefreshPlansCommand { get; } + public DelegateCommand RefreshChartDemoCommand { get; } - private async Task LoadPlansAsync() + + + private async Task LoadLocalDataAsync(bool showSuccess) + { + IsLoading = true; + try + { - _allPlans = await _operationService.GetMixingProductionPlansAsync(); - BuildAllShiftOptions(); + + _allPlans = await _planService.GetAllCachedAsync(); + + _allStds = await _stdService.GetAllCachedAsync(); + RefreshMachineOptions(); - Growl.Success("密炼生产计划已刷新"); + + if (showSuccess) + + Growl.Success("本地密炼计划与实验标准已刷新"); + } + catch (Exception ex) + { - Growl.Error($"加载密炼生产计划失败:{ex.Message}"); + + Growl.Error($"加载本地数据失败:{ex.Message}"); + } + finally + { + IsLoading = false; + } + } - private void BuildAllShiftOptions() + + + private async Task ReloadLocalDataQuietAsync() + { - _allShiftOptions.Clear(); - foreach (var row in _allPlans) + + try + { - if (string.IsNullOrWhiteSpace(row.PlanId)) continue; - var shiftCode = row.ShiftFlag?.ToString() ?? string.Empty; - _allShiftOptions.Add(new MixingPlanShiftOption - { - PlanRowId = row.Id ?? string.Empty, - MachineId = row.MachineId, - MachineName = row.MachineName, - ShiftKey = shiftCode, - ShiftCode = shiftCode, - ShiftName = row.ShiftFlagText, - OrderDate = row.PlanDate, - PlanId = row.PlanId, - OrderNo = row.OrderNo, - FormulaName = row.FormulaName, - MaterialName = row.MaterialName - }); + + _allPlans = await _planService.GetAllCachedAsync(); + + _allStds = await _stdService.GetAllCachedAsync(); + + RefreshMachineOptions(); + + RefreshStdOptions(); + } + + catch (Exception ex) + + { + + _logger.Warning($"[胶料快检记录] 本地数据刷新失败:{ex.Message}"); + + } + } - private IEnumerable FilteredByDate => - _allShiftOptions.Where(o => o.OrderDate?.Date == MixingDate.Date); + + + private IEnumerable FilteredByDate => + + _allPlans.Where(p => p.PlanDate?.Date == MixingDate.Date); + + private void RefreshMachineOptions() + { + MachineOptions.Clear(); + foreach (var name in FilteredByDate.Select(o => o.MachineName).Where(n => !string.IsNullOrWhiteSpace(n)).Distinct().OrderBy(n => n)) + MachineOptions.Add(name!); + if (SelectedMachine != null && !MachineOptions.Contains(SelectedMachine)) + SelectedMachine = null; + if (SelectedMachine == null && MachineOptions.Count > 0) + SelectedMachine = MachineOptions[0]; + else + RefreshShiftOptions(); + } + + private void RefreshShiftOptions() + { + ShiftOptions.Clear(); + var machine = SelectedMachine; + var shifts = FilteredByDate + .Where(o => string.IsNullOrWhiteSpace(machine) || o.MachineName == machine) - .GroupBy(o => o.ShiftCode) + + .GroupBy(o => o.ShiftFlag?.ToString() ?? string.Empty) + .Select(g => g.First()) - .OrderBy(o => o.ShiftCode); + + .OrderBy(o => o.ShiftFlag); + foreach (var s in shifts) - ShiftOptions.Add(new WorkShiftOption(s.ShiftCode, s.ShiftName)); + + ShiftOptions.Add(new WorkShiftOption(s.ShiftFlag?.ToString() ?? string.Empty, s.ShiftFlagText)); + if (SelectedShift != null && !ShiftOptions.Any(x => x.Code == SelectedShift.Code)) + SelectedShift = null; + if (SelectedShift == null && ShiftOptions.Count > 0) + SelectedShift = ShiftOptions[0]; + else + RefreshPlanOptions(); + } + + private void RefreshPlanOptions() + { + PlanOptions.Clear(); + var machine = SelectedMachine; + var shiftCode = SelectedShift?.Code; - foreach (var o in FilteredByDate + + foreach (var p in FilteredByDate + .Where(x => string.IsNullOrWhiteSpace(machine) || x.MachineName == machine) - .Where(x => string.IsNullOrWhiteSpace(shiftCode) || x.ShiftCode == shiftCode) - .OrderBy(x => x.OrderNo)) - PlanOptions.Add(o); - if (SelectedPlan != null && PlanOptions.All(p => p.PlanId != SelectedPlan.PlanId)) + + .Where(x => string.IsNullOrWhiteSpace(shiftCode) || (x.ShiftFlag?.ToString() ?? string.Empty) == shiftCode) + + .Where(x => !string.IsNullOrWhiteSpace(x.PlanMaterialNo)) + + .OrderBy(x => x.PlanMaterialNo)) + + PlanOptions.Add(p); + + if (SelectedPlan != null && PlanOptions.All(p => p.Id != SelectedPlan.Id)) + SelectedPlan = null; + if (SelectedPlan == null && PlanOptions.Count > 0) + SelectedPlan = PlanOptions[0]; + } - private void ClearPlanSelection() + + + private void ClearPlanAndStdSelection() + { + _selectedPlan = null; + RaisePropertyChanged(nameof(SelectedPlan)); - RaisePropertyChanged(nameof(ProductionOrderNo)); + RaisePropertyChanged(nameof(MachineName)); + RaisePropertyChanged(nameof(WorkShiftDisplay)); + RaisePropertyChanged(nameof(RubberMaterialName)); - ClearStdAndResults(); + + ClearStdSelection(); + } + + + private void ClearStdSelection() + + { + + _selectedStd = null; + + RaisePropertyChanged(nameof(SelectedStd)); + + TestMethodName = null; + + ClearStdAndResults(); + + StdOptions.Clear(); + + } + + + private void ApplySelectedPlan() + { - RaisePropertyChanged(nameof(ProductionOrderNo)); + RaisePropertyChanged(nameof(MachineName)); + RaisePropertyChanged(nameof(WorkShiftDisplay)); + RaisePropertyChanged(nameof(RubberMaterialName)); - _ = LoadStdAsync(); + + ClearStdSelection(); + + RefreshStdOptions(); + } - private async Task LoadStdAsync() + + + private void RefreshStdOptions() + { - DataPointColumns.Clear(); - InspectRows.Clear(); - _currentStd = null; - InspectColumnsChanged?.Invoke(); + + StdOptions.Clear(); var rubberName = RubberMaterialName; + if (string.IsNullOrWhiteSpace(rubberName)) return; - IsLoading = true; - try - { - _currentStd = await _operationService.GetStdByRubberMaterialNameAsync(rubberName); - if (_currentStd?.LineList == null || _currentStd.LineList.Count == 0) - { - Growl.Warning($"未找到胶料「{rubberName}」的使用中且已批准的快检实验标准"); - return; - } - foreach (var line in _currentStd.LineList.OrderBy(l => l.SortNo ?? 0)) - DataPointColumns.Add(line); - InspectColumnsChanged?.Invoke(); - AddInspectRow(); - AddInspectRowCommand.RaiseCanExecuteChanged(); - } - catch (Exception ex) - { - Growl.Error($"加载实验标准失败:{ex.Message}"); - } - finally - { - IsLoading = false; - } + + + foreach (var std in FilterApplicableStds(rubberName).OrderBy(s => s.StdName)) + + StdOptions.Add(std); + + + + if (StdOptions.Count == 0) + + Growl.Warning($"未找到胶料「{rubberName}」的使用中且已批准的快检实验标准,请先在「胶料快检实验标准」中同步数据"); + + RecalculateOverallInspectResult(); } + + + private IEnumerable FilterApplicableStds(string rubberMaterialName) + + { + + var name = rubberMaterialName.Trim(); + + return _allStds.Where(std => + + string.Equals(std.RubberMaterialName?.Trim(), name, StringComparison.OrdinalIgnoreCase) + + && std.EnableStatus == "1" + + && std.AuditStatus == "1"); + + } + + + + private async Task ApplySelectedStdAsync() + + { + + DataPointColumns.Clear(); + + InspectRows.Clear(); + + _currentStd = null; + + TestMethodName = null; + + InspectColumnsChanged?.Invoke(); + + RecalculateOverallInspectResult(); + + if (SelectedStd == null || string.IsNullOrWhiteSpace(SelectedStd.Id)) return; + + + + IsLoading = true; + + try + + { + + _currentStd = await _stdService.GetWithLinesAsync(SelectedStd.Id); + + if (_currentStd == null) + + { + + Growl.Warning("所选实验标准在本地缓存中不存在,请刷新本地数据"); + + return; + + } + + + + TestMethodName = _currentStd.TestMethodName; + + + + if (_currentStd.LineList == null || _currentStd.LineList.Count == 0) + + { + + Growl.Warning($"标准「{_currentStd.StdName}」明细未同步到本地,请联网后重选,或先在「胶料快检实验标准」中查看该标准详情"); + + return; + + } + + + + foreach (var line in _currentStd.LineList.OrderBy(l => l.SortNo ?? 0)) + + DataPointColumns.Add(line); + + InspectColumnsChanged?.Invoke(); + + InitInspectRowsFromTimes(); + + AddInspectRowCommand.RaiseCanExecuteChanged(); + + } + + catch (Exception ex) + + { + + Growl.Error($"加载实验标准失败:{ex.Message}"); + + } + + finally + + { + + IsLoading = false; + + RecalculateOverallInspectResult(); + + } + + } + + + private void ClearStdAndResults() + { + DataPointColumns.Clear(); + InspectRows.Clear(); + _currentStd = null; + InspectColumnsChanged?.Invoke(); + + RecalculateOverallInspectResult(); + } - /// 打开页面或中间库无数据时填充曲线演示数据(5 点对应 0~2min) + + private void FillRandomChartData() { UpperTempValues.Clear(); @@ -429,254 +998,538 @@ public class RubberQuickTestOperationViewModel : BaseViewModel for (int i = 0; i < ChartPointCount; i++) { - var upper = 192 + _rnd.NextDouble() * 8; - var lower = upper - 2 - _rnd.NextDouble() * 2; - var torque = Math.Min(14, i * 2.5 + _rnd.NextDouble() * 2.5); - UpperTempValues.Add(Math.Round(upper, 2)); - LowerTempValues.Add(Math.Round(lower, 2)); - TorqueValues.Add(Math.Round(torque, 2)); + var time = ChartTimeMinutes[i]; + var upper = 189 + _rnd.NextDouble() * 12; + var lower = Math.Max(189, upper - 2 - _rnd.NextDouble() * 2); + var torque = Math.Min(14.8, i * 2.5 + _rnd.NextDouble() * 2.5); + UpperTempValues.Add(new ObservablePoint(time, Math.Round(upper, 2))); + LowerTempValues.Add(new ObservablePoint(time, Math.Round(lower, 2))); + TorqueValues.Add(new ObservablePoint(time, Math.Round(torque, 2))); } - UpperMoldTemp = UpperTempValues[^1]; - LowerMoldTemp = LowerTempValues[^1]; - TorqueS = TorqueValues[^1]; + UpperMoldTemp = UpperTempValues[^1].Y ?? 0; + LowerMoldTemp = LowerTempValues[^1].Y ?? 0; + TorqueS = TorqueValues[^1].Y ?? 0; + } + + + + private void InitInspectRowsFromTimes() + { + InspectRows.Clear(); + var times = 1; + if (TryParseInspectTimes(out var n, out _)) + times = n; + for (var i = 0; i < times; i++) + AddInspectRow(); + } + + private void RenumberInspectRows() + { + for (var i = 0; i < InspectRows.Count; i++) + InspectRows[i].RowNo = $"{i + 1}_1"; } private void AddInspectRow() + { + var rowIndex = InspectRows.Count + 1; + var row = new QuickTestInspectRowViewModel { RowNo = $"{rowIndex}_1" }; + foreach (var col in DataPointColumns) + { + var cell = new QuickTestInspectCellViewModel + { + DataPointId = col.DataPointId, + PointName = col.PointName ?? string.Empty, + LowerLimit = col.LowerLimit, + UpperLimit = col.UpperLimit + }; - cell.ValueChanged += _ => row.RecalculateResult(); + + cell.ValueChanged += _ => + { + row.RecalculateResult(); + RecalculateOverallInspectResult(); + }; + row.Cells.Add(cell); + } + row.RecalculateResult(); + InspectRows.Add(row); + SaveCommand.RaiseCanExecuteChanged(); + + RecalculateOverallInspectResult(); + } + + private void RemoveInspectRow(QuickTestInspectRowViewModel? row) + { + if (row == null) return; + InspectRows.Remove(row); + SelectedInspectRow = null; + + RenumberInspectRows(); + SaveCommand.RaiseCanExecuteChanged(); + + RecalculateOverallInspectResult(); + } + + private async Task SaveAsync() + { + if (string.IsNullOrWhiteSpace(TrainNo)) + { + Growl.Warning("请填写车次"); + return; + } - if (string.IsNullOrWhiteSpace(ProductionOrderNo)) + + if (SelectedPlan == null) + { - Growl.Warning("请选择密炼计划以带出生产订单号"); + + Growl.Warning("请选择密炼计划"); + return; + } + if (string.IsNullOrWhiteSpace(RubberMaterialName)) + { + Growl.Warning("请先选择密炼计划以带出胶料名称"); + return; + } - if (_currentStd == null) + + if (SelectedStd == null || _currentStd == null) + { - Growl.Warning("未加载实验标准,无法保存"); + + Growl.Warning("请选择实验标准"); + return; + } + + if (InspectRows.Any(r => r.InspectResultText == "待填写" || string.IsNullOrWhiteSpace(r.InspectResultText))) + { + Growl.Warning("请手填全部检验行的检测值后再保存"); + return; + } + + if (!TryParseInspectTimes(out var inspectTimes, out var inspectTimesError)) + { + Growl.Warning(inspectTimesError); + return; + } + + var lineList = BuildAveragedLineList(); + if (lineList.Count == 0) + { + Growl.Warning("无法根据试验结果计算明细数据"); + return; + } + + var rawLineList = BuildRawLineList(); + if (rawLineList.Count == 0) + { + Growl.Warning("无法生成试验结果原始数据"); + return; + } + + var user = AppSession.CurrentUser; + IsLoading = true; + try + { + var record = BuildSaveRecord(lineList, rawLineList, inspectTimes, user); - await _operationService.SaveRecordAsync(record); - Growl.Success("快检记录已保存到 MES"); + + var recordNo = await _operationService.SaveRecordAsync(record); + + RecordNo = recordNo; + + Growl.Success(string.IsNullOrWhiteSpace(recordNo) + + ? "胶料快检记录已保存到 MES" + + : $"胶料快检记录已保存,单号:{recordNo}"); + InspectRows.Clear(); + SaveCommand.RaiseCanExecuteChanged(); + } + catch (Exception ex) + { + Growl.Error($"保存失败:{ex.Message}"); + } + finally + { + IsLoading = false; + } + } + + private bool TryParseInspectTimes(out int value, out string error) + { + error = string.Empty; + var text = string.IsNullOrWhiteSpace(InspectTimesText) ? "1" : InspectTimesText.Trim(); + if (!int.TryParse(text, out var n) || n <= 0) + { + error = "试验次数须填写正整数"; + value = 0; + return false; + } + + value = n; + return true; + } - /// 试验结果各数据点检测值取平均,写入快检记录明细 + + private List BuildAveragedLineList() + { + var lines = new List(); + for (int i = 0; i < DataPointColumns.Count; i++) + { + var col = DataPointColumns[i]; + var values = InspectRows + .Where(r => i < r.Cells.Count && r.Cells[i].Value != null) + .Select(r => r.Cells[i].Value!.Value) + .ToList(); + if (values.Count == 0) + continue; + + var avg = values.Average(v => (double)v); + var avgDecimal = Math.Round((decimal)avg, 6); + + var line = new MesXslRubberQuickTestRecordLine { SortNo = i }; + if (!string.IsNullOrWhiteSpace(col.DataPointId)) + line.DataPointId = col.DataPointId; + if (!string.IsNullOrWhiteSpace(col.PointName)) + line.InspectItem = col.PointName; + if (col.LowerLimit != null) + line.LowerLimit = col.LowerLimit; + if (col.UpperLimit != null) + line.UpperLimit = col.UpperLimit; + line.InspectValue = avgDecimal; + lines.Add(line); + } + return lines; + } - /// 试验结果全部检测值写入原始数据明细 + + private List BuildRawLineList() + { + var rawLines = new List(); + int sort = 0; + foreach (var row in InspectRows) + { + for (int i = 0; i < row.Cells.Count; i++) + { + var cell = row.Cells[i]; + if (cell.Value == null) + continue; + + var raw = new MesXslRubberQuickTestRecordRawLine { SortNo = sort++ }; + if (!string.IsNullOrWhiteSpace(row.RowNo)) + raw.RowNo = row.RowNo; + if (!string.IsNullOrWhiteSpace(cell.DataPointId)) + raw.DataPointId = cell.DataPointId; + if (!string.IsNullOrWhiteSpace(cell.PointName)) + raw.InspectItem = cell.PointName; + if (cell.LowerLimit != null) + raw.LowerLimit = cell.LowerLimit; + if (cell.UpperLimit != null) + raw.UpperLimit = cell.UpperLimit; + raw.InspectValue = cell.Value; + raw.RowInspectResult = row.InspectResultCode; + rawLines.Add(raw); + } + } + return rawLines; + } - /// 主表检验结果:任一行不合格则不合格 - private static string JudgeInspectResultFromRows(IEnumerable rows) + + + private bool HasExperimentStandardForRubber(string? rubberMaterialName) { - if (!rows.Any()) - return "0"; - return rows.Any(r => r.InspectResultCode != "1") ? "0" : "1"; + if (string.IsNullOrWhiteSpace(rubberMaterialName)) return false; + return FilterApplicableStds(rubberMaterialName).Any(); + } + + private void RecalculateOverallInspectResult() + { + string display; + string code; + + if (!HasExperimentStandardForRubber(RubberMaterialName) + || _currentStd == null + || DataPointColumns.Count == 0) + { + display = "不合格"; + code = "0"; + } + else if (InspectRows.Count == 0 + || InspectRows.Any(r => !string.Equals(r.InspectResultText, "合格", StringComparison.Ordinal))) + { + display = "不合格"; + code = "0"; + } + else + { + display = "合格"; + code = "1"; + } + + OverallInspectResultCode = code; + OverallInspectResultDisplay = display; } private MesXslRubberQuickTestRecord BuildSaveRecord( + List lineList, + List rawLineList, + int inspectTimes, + SysUser? user) + { + var record = new MesXslRubberQuickTestRecord + { + LineList = lineList, + RawLineList = rawLineList, + InspectTime = DateTime.Now, - InspectResult = JudgeInspectResultFromRows(InspectRows) + + InspectResult = OverallInspectResultCode + }; + + if (!string.IsNullOrWhiteSpace(_currentStd?.RubberMaterialId)) + record.RubberMaterialId = _currentStd.RubberMaterialId; + if (!string.IsNullOrWhiteSpace(RubberMaterialName)) + record.RubberMaterialName = RubberMaterialName; + if (!string.IsNullOrWhiteSpace(_currentStd?.Id)) + record.StdId = _currentStd.Id; + + if (!string.IsNullOrWhiteSpace(_selectedPlan?.MachineId)) + record.ProdEquipmentLedgerId = _selectedPlan.MachineId; + if (!string.IsNullOrWhiteSpace(MachineName)) + record.ProdEquipmentName = MachineName; + + record.ProductionDate = MixingDate; + + if (!string.IsNullOrWhiteSpace(TrainNo)) + record.TrainNo = TrainNo.Trim(); + + if (SelectedShift != null && !string.IsNullOrWhiteSpace(SelectedShift.Code)) + record.WorkShift = SelectedShift.Code; + + record.InspectTimes = inspectTimes; - if (!string.IsNullOrWhiteSpace(ProductionOrderNo)) - record.ProductionPlanNo = ProductionOrderNo; + + + if (!string.IsNullOrWhiteSpace(_selectedPlan?.PlanMaterialNo)) + + record.ProductionPlanNo = _selectedPlan.PlanMaterialNo; + + var inspectorId = user?.JeecgBizUserId ?? (user != null ? user.Id.ToString() : null); + if (!string.IsNullOrWhiteSpace(inspectorId)) + record.InspectorUserId = inspectorId; + if (!string.IsNullOrWhiteSpace(user?.Account)) + record.InspectorUsername = user.Account; + if (!string.IsNullOrWhiteSpace(user?.RealName)) + record.InspectorRealname = user.RealName; + + return record; + } + + private static Axis[] BuildTimeAxis() => new[] { new Axis @@ -684,7 +1537,8 @@ public class RubberQuickTestOperationViewModel : BaseViewModel Name = "时间(min)", MinLimit = 0, MaxLimit = 2, - Labels = new[] { "0", "0.5", "1", "1.5", "2" }, + MinStep = 0.5, + ForceStepToMin = true, LabelsPaint = new SolidColorPaint(SKColors.Gray), NamePaint = new SolidColorPaint(SKColors.Gray) } @@ -697,53 +1551,110 @@ public class RubberQuickTestOperationViewModel : BaseViewModel Name = "温度(℃)", MinLimit = 189, MaxLimit = 201, - Labeler = v => v switch - { - 189 => "189", - 192 => "192", - 195 => "195", - 198 => "198", - 201 => "201", - _ => string.Empty - }, + MinStep = 3, + ForceStepToMin = true, + Labeler = v => FormatAxisTick(v, 189, 192, 195, 198, 201), LabelsPaint = new SolidColorPaint(SKColors.Gray), NamePaint = new SolidColorPaint(SKColors.Gray) } }; + private static readonly double[] TorqueYTicks = { 0.0, 3.0, 5.9, 8.9, 11.8, 14.8 }; + private static Axis[] BuildTorqueYAxis() => new[] { new Axis { Name = "S'(dNm)", MinLimit = 0, - MaxLimit = 14, - Labeler = v => v switch - { - 0 => "0", - 3 => "3", - 6 => "6", - 8 => "8", - 11 => "11", - 14 => "14", - _ => string.Empty - }, + MaxLimit = 14.8, + CustomSeparators = TorqueYTicks, + Labeler = FormatTorqueAxisLabel, LabelsPaint = new SolidColorPaint(SKColors.Gray), NamePaint = new SolidColorPaint(SKColors.Gray) } }; - public new void Destroy() => base.Destroy(); -} - -public class WorkShiftOption -{ - public WorkShiftOption(string code, string name) + private static string FormatTorqueAxisLabel(double value) { - Code = code; - Name = name; + foreach (var tick in TorqueYTicks) + { + if (Math.Abs(value - tick) > 0.05) continue; + return tick.ToString("0.0"); + } + return string.Empty; } - public string Code { get; } - public string Name { get; } + private static string FormatAxisTick(double value, params double[] ticks) + { + foreach (var tick in ticks) + { + if (Math.Abs(value - tick) > 0.01) continue; + return Math.Abs(tick - Math.Round(tick)) < 0.001 + ? ((int)Math.Round(tick)).ToString() + : tick.ToString("0.#"); + } + return string.Empty; + } + + + + protected override void CleanUp() + + { + + if (_planChangedToken != null) + + { + + _eventAggregator.GetEvent().Unsubscribe(_planChangedToken); + + _planChangedToken = null; + + } + + if (_stdChangedToken != null) + + { + + _eventAggregator.GetEvent().Unsubscribe(_stdChangedToken); + + _stdChangedToken = null; + + } + + base.CleanUp(); + + } + + + + public new void Destroy() => base.Destroy(); + } + + + +public class WorkShiftOption + +{ + + public WorkShiftOption(string code, string name) + + { + + Code = code; + + Name = name; + + } + + + + public string Code { get; } + + public string Name { get; } + +} + + diff --git a/yy-admin-master/YY.Admin/Views/MixingProductionPlan/MixingProductionPlanListView.xaml b/yy-admin-master/YY.Admin/Views/MixingProductionPlan/MixingProductionPlanListView.xaml index 24752f33..82f5d295 100644 --- a/yy-admin-master/YY.Admin/Views/MixingProductionPlan/MixingProductionPlanListView.xaml +++ b/yy-admin-master/YY.Admin/Views/MixingProductionPlan/MixingProductionPlanListView.xaml @@ -112,12 +112,14 @@ VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"> - - - - - - + + + + + + + + diff --git a/yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml b/yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml index e16c3a26..9dcd6a7c 100644 --- a/yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml +++ b/yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml @@ -28,7 +28,7 @@ - + @@ -40,19 +40,19 @@ - - - + + + - + - + - + @@ -62,7 +62,7 @@ - +