From 94b15e5237d9588c0f339893f035b4ac1f5613b0 Mon Sep 17 00:00:00 2001 From: jiangxh <1217934998@qq.com> Date: Wed, 17 Jun 2026 15:41:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A1=8C=E9=9D=A2=E7=AB=AF=E8=83=B6=E6=96=99?= =?UTF-8?q?=E5=BF=AB=E6=A3=80=E5=AE=9E=E9=AA=8C=E6=A0=87=E5=87=86=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/jeecg/config/shiro/ShiroConfig.java | 6 + .../jeecg-module-xslmes/doc/代码修改日志 | 8 + .../RubberQuickTestStdApprovalCallback.java | 10 +- .../MesXslDesktopAnonController.java | 112 +++ ...MesXslRubberQuickTestRecordController.java | 10 + .../MesXslRubberQuickTestStdController.java | 31 + .../entity/MesXslRubberQuickTestRecord.java | 4 + .../MesXslRubberQuickTestRecordRawLine.java | 72 ++ ...XslRubberQuickTestRecordRawLineMapper.java | 6 + .../IMesXslRubberQuickTestRecordService.java | 3 + .../service/MesXslStompNotifyService.java | 16 + ...esXslRubberQuickTestRecordServiceImpl.java | 42 + .../MesXslRubberQuickTestStdServiceImpl.java | 5 + ..._xsl_rubber_quick_test_record_raw_line.sql | 21 + ..._rubber_quick_test_std_tenant_backfill.sql | 11 + ...slRubberQuickTestStdMixerPsSelectModal.vue | 9 +- .../Events/RubberQuickTestStdChangedEvent.cs | 11 + .../IRubberQuickTestOperationService.cs | 13 + .../Services/IRubberQuickTestStdService.cs | 24 + .../Entity/MesXslMixingProductionPlan.cs | 28 + .../Entity/MesXslRubberQuickTestRecord.cs | 24 + .../Entity/MesXslRubberQuickTestRecordLine.cs | 13 + .../MesXslRubberQuickTestRecordRawLine.cs | 17 + .../Entity/MesXslRubberQuickTestStd.cs | 32 + .../Entity/MesXslRubberQuickTestStdLine.cs | 15 + .../YY.Admin.Core/SeedData/SysMenuSeedData.cs | 4 + .../SeedData/SysTenantMenuSeedData.cs | 2 + .../RubberQuickTestOperationService.cs | 117 +++ .../RubberQuickTestStdService.cs | 302 +++++++ .../RubberQuickTestStdSyncCoordinator.cs | 73 ++ .../Hubs/StompWebSocketService.cs | 4 + .../YY.Admin/Module/NavigationExtensions.cs | 6 + yy-admin-master/YY.Admin/Module/SyncModule.cs | 11 + .../ViewModels/Control/MenuTreeViewModel.cs | 10 + .../RubberQuickTestOperationViewModel.cs | 755 ++++++++++++++++++ ...RubberQuickTestStdDetailDialogViewModel.cs | 40 + .../RubberQuickTestStdListViewModel.cs | 166 ++++ .../RubberQuickTestOperationView.xaml | 301 +++++++ .../RubberQuickTestOperationView.xaml.cs | 72 ++ .../RubberQuickTestStdDetailDialogView.xaml | 97 +++ ...RubberQuickTestStdDetailDialogView.xaml.cs | 11 + .../RubberQuickTestStdListView.xaml | 128 +++ .../RubberQuickTestStdListView.xaml.cs | 11 + 43 files changed, 2651 insertions(+), 2 deletions(-) create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecordRawLine.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslRubberQuickTestRecordRawLineMapper.java create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_151__mes_xsl_rubber_quick_test_record_raw_line.sql create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_152__mes_xsl_rubber_quick_test_std_tenant_backfill.sql create mode 100644 yy-admin-master/YY.Admin.Core/Core/Events/RubberQuickTestStdChangedEvent.cs create mode 100644 yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestOperationService.cs create mode 100644 yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestStdService.cs create mode 100644 yy-admin-master/YY.Admin.Core/Entity/MesXslMixingProductionPlan.cs create mode 100644 yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecord.cs create mode 100644 yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordLine.cs create mode 100644 yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordRawLine.cs create mode 100644 yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStd.cs create mode 100644 yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStdLine.cs create mode 100644 yy-admin-master/YY.Admin.Services/Service/RubberQuickTest/RubberQuickTestOperationService.cs create mode 100644 yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdService.cs create mode 100644 yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdSyncCoordinator.cs create mode 100644 yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs create mode 100644 yy-admin-master/YY.Admin/ViewModels/RubberQuickTestStd/RubberQuickTestStdDetailDialogViewModel.cs create mode 100644 yy-admin-master/YY.Admin/ViewModels/RubberQuickTestStd/RubberQuickTestStdListViewModel.cs create mode 100644 yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml create mode 100644 yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml.cs create mode 100644 yy-admin-master/YY.Admin/Views/RubberQuickTestStd/RubberQuickTestStdDetailDialogView.xaml create mode 100644 yy-admin-master/YY.Admin/Views/RubberQuickTestStd/RubberQuickTestStdDetailDialogView.xaml.cs create mode 100644 yy-admin-master/YY.Admin/Views/RubberQuickTestStd/RubberQuickTestStdListView.xaml create mode 100644 yy-admin-master/YY.Admin/Views/RubberQuickTestStd/RubberQuickTestStdListView.xaml.cs diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java index 126f6a7b..874d9b1c 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java @@ -217,6 +217,12 @@ public class ShiroConfig { filterChainDefinitionMap.put("/xslmes/mesXslUnit/anon/**", "anon"); // MES密炼物料管理免密接口(供桌面端调用) filterChainDefinitionMap.put("/mes/material/mixerMaterial/anon/**", "anon"); + // MES密炼生产计划维护免密接口(供桌面端快检记录调用) + filterChainDefinitionMap.put("/xslmes/mesXslMixingProductionPlan/anon/**", "anon"); + // MES胶料快检实验标准免密接口(供桌面端快检记录调用) + filterChainDefinitionMap.put("/xslmes/mesXslRubberQuickTestStd/anon/**", "anon"); + // MES胶料快检记录免密接口(供桌面端快检记录调用) + filterChainDefinitionMap.put("/xslmes/mesXslRubberQuickTestRecord/anon/**", "anon"); // 打印模板免密接口(供桌面端调用) filterChainDefinitionMap.put("/print/template/anon/**", "anon"); filterChainDefinitionMap.put("/print/bizTemplateBind/anon/**", "anon"); diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 index 88ba16f6..be04827c 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 @@ -1098,3 +1098,11 @@ jeecgboot-vue3/src/views/xslmes/mesXslEquipDowntimeRecord/components/MesXslEquip 修改:prod 全局改为 SELECT 1;McsDataSourceManager 创建/恢复 SQL Server 数据源时显式设置 validationQuery=SELECT 1。 jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/datasource/McsDataSourceManager.java + +-- author:jiangxh---date:20260617--for: 【快检实验标准】补齐 tenant_id 为空的历史数据并恢复租户过滤 --- +原因:一条快检实验标准 tenant_id 为 NULL,桌面端按 tenantId=1002 拉取时漏掉该条。 +修改:Flyway 将 NULL tenant_id 对齐为 1002;新增保存时自动写入 tenant_id;恢复 anon/list 与桌面端 tenantId 查询参数。 +jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_152__mes_xsl_rubber_quick_test_std_tenant_backfill.sql +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDesktopAnonController.java +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestStdServiceImpl.java +yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdService.cs diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/callback/impl/RubberQuickTestStdApprovalCallback.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/callback/impl/RubberQuickTestStdApprovalCallback.java index 303b13f7..111f611f 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/callback/impl/RubberQuickTestStdApprovalCallback.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/callback/impl/RubberQuickTestStdApprovalCallback.java @@ -7,6 +7,7 @@ import org.jeecg.modules.xslmes.approval.callback.IApprovalBizCallback; import org.jeecg.modules.xslmes.common.XslMesBizConstants; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService; +import org.jeecg.modules.xslmes.service.MesXslStompNotifyService; import org.springframework.stereotype.Component; /** @@ -25,9 +26,13 @@ import org.springframework.stereotype.Component; public class RubberQuickTestStdApprovalCallback implements IApprovalBizCallback { private final IMesXslRubberQuickTestStdService stdService; + private final MesXslStompNotifyService stompNotify; - public RubberQuickTestStdApprovalCallback(IMesXslRubberQuickTestStdService stdService) { + public RubberQuickTestStdApprovalCallback( + IMesXslRubberQuickTestStdService stdService, + MesXslStompNotifyService stompNotify) { this.stdService = stdService; + this.stompNotify = stompNotify; } @Override @@ -55,5 +60,8 @@ public class RubberQuickTestStdApprovalCallback implements IApprovalBizCallback .eq(MesXslRubberQuickTestStd::getId, bizDataId) .set(MesXslRubberQuickTestStd::getAuditStatus, auditStatus) .update(); + //update-begin---author:jiangxh ---date:20260617 for:【快检实验标准】审批联动 STOMP 同步桌面端----------- + stompNotify.publishRubberQuickTestStdChanged("audit", bizDataId); + //update-end---author:jiangxh ---date:20260617 for:【快检实验标准】审批联动 STOMP 同步桌面端----------- } } 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 538091f8..0937563b 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 @@ -1,5 +1,6 @@ package org.jeecg.modules.xslmes.controller; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -21,6 +22,7 @@ import org.jeecg.modules.print.entity.PrintTemplate; import org.jeecg.modules.print.service.IPrintBizTemplateBindService; import org.jeecg.modules.print.service.IPrintTemplateService; import org.jeecg.modules.print.util.PrintBizDataMappingUtil; +import org.jeecg.modules.xslmes.common.XslMesBizConstants; import org.jeecg.modules.xslmes.constant.MesXslCustomerBizStatus; import org.jeecg.modules.xslmes.constant.MesXslPrintConstants; import org.jeecg.modules.xslmes.entity.MesXslCustomer; @@ -32,6 +34,11 @@ import org.jeecg.modules.xslmes.entity.MesXslUnit; 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.MesXslRubberQuickTestRecord; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStdLine; import org.jeecg.modules.xslmes.entity.MesXslWeightRecord; import org.jeecg.modules.xslmes.service.IMesXslCustomerService; import org.jeecg.modules.xslmes.service.IMesXslRawMaterialCardService; @@ -42,6 +49,9 @@ import org.jeecg.modules.xslmes.service.IMesXslUnitService; 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.IMesXslRubberQuickTestRecordService; +import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService; import org.jeecg.modules.xslmes.service.IMesXslWeightRecordService; import org.jeecg.modules.xslmes.service.MesXslStompNotifyService; import org.jeecg.modules.xslmes.vo.MesXslRawMaterialCardBriefVO; @@ -87,6 +97,9 @@ public class MesXslDesktopAnonController { private final IPrintBizTemplateBindService printBizTemplateBindService; private final IPrintTemplateService printTemplateService; private final ObjectMapper objectMapper; + private final IMesXslMixingProductionPlanService mixingProductionPlanService; + private final IMesXslRubberQuickTestStdService rubberQuickTestStdService; + private final IMesXslRubberQuickTestRecordService rubberQuickTestRecordService; // ═══════════════════════════ 车辆管理 ═══════════════════════════ @@ -925,6 +938,105 @@ public class MesXslDesktopAnonController { } //update-end---author:cursor ---date:20250602 for:【密炼物料皮重策略】桌面端单位下拉只读----------- + //update-begin---author:jiangxh ---date:2026-06-17 for:【快检记录】桌面端密炼生产计划只读----------- + @Operation(summary = "密炼生产计划维护-免密分页列表查询(供桌面端快检记录筛选)") + @GetMapping("/xslmes/mesXslMixingProductionPlan/anon/list") + public Result> mixingProductionPlanAnonList( + MesXslMixingProductionPlan model, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "500") Integer pageSize, + HttpServletRequest req) { + QueryWrapper qw = QueryGenerator.initQueryWrapper(model, req.getParameterMap()); + qw.orderByAsc("sort_no").orderByAsc("create_time"); + IPage page = + mixingProductionPlanService.page(new Page<>(pageNo, pageSize), qw); + return Result.OK(page); + } + //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】桌面端密炼生产计划只读----------- + + //update-begin---author:jiangxh ---date:2026-06-17 for:【快检实验标准】桌面端只读列表与详情----------- + @Operation(summary = "胶料快检实验标准-免密分页列表") + @GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/list") + public Result> rubberQuickTestStdAnonList( + MesXslRubberQuickTestStd model, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, + HttpServletRequest req) { + QueryWrapper qw = QueryGenerator.initQueryWrapper(model, req.getParameterMap()); + qw.orderByDesc("create_time"); + IPage page = rubberQuickTestStdService.page(new Page<>(pageNo, pageSize), qw); + return Result.OK(page); + } + + @Operation(summary = "胶料快检实验标准-免密通过id查询(含明细)") + @GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/queryById") + public Result rubberQuickTestStdAnonQueryById(@RequestParam(name = "id") String id) { + MesXslRubberQuickTestStd entity = rubberQuickTestStdService.getById(id); + if (entity == null) { + return Result.error("未找到对应数据"); + } + entity.setLineList(rubberQuickTestStdService.selectLinesByStdId(id)); + return Result.OK(entity); + } + //update-end---author:jiangxh ---date:2026-06-17 for:【快检实验标准】桌面端只读列表与详情----------- + + //update-begin---author:jiangxh ---date:2026-06-17 for:【快检记录】桌面端胶料快检实验标准查询----------- + private static final String RUBBER_QUICK_TEST_STD_ENABLE_IN_USE = "1"; + + @Operation(summary = "胶料快检实验标准-免密按胶料名称查询使用中标准及明细") + @GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/queryByRubberMaterialName") + public Result rubberQuickTestStdAnonQueryByRubberMaterialName( + @RequestParam(name = "rubberMaterialName") String rubberMaterialName) { + if (oConvertUtils.isEmpty(rubberMaterialName)) { + return Result.error("胶料名称不能为空"); + } + String name = rubberMaterialName.trim(); + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(MesXslRubberQuickTestStd::getRubberMaterialName, name); + qw.eq(MesXslRubberQuickTestStd::getEnableStatus, RUBBER_QUICK_TEST_STD_ENABLE_IN_USE); + qw.eq(MesXslRubberQuickTestStd::getAuditStatus, XslMesBizConstants.RUBBER_QUICK_TEST_STD_AUDIT_APPROVED); + qw.orderByDesc(MesXslRubberQuickTestStd::getCreateTime); + MesXslRubberQuickTestStd std = rubberQuickTestStdService.getOne(qw, false); + if (std == null) { + return Result.error("未找到胶料「" + name + "」对应的使用中且已批准的快检实验标准"); + } + std.setLineList(rubberQuickTestStdService.selectLinesByStdId(std.getId())); + return Result.OK(std); + } + + @Operation(summary = "胶料快检实验标准-免密查询明细") + @GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/queryLineListByStdId") + public Result> rubberQuickTestStdAnonQueryLineListByStdId( + @RequestParam(name = "id") String id) { + return Result.OK(rubberQuickTestStdService.selectLinesByStdId(id)); + } + //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】桌面端胶料快检实验标准查询----------- + + //update-begin---author:jiangxh ---date:2026-06-17 for:【快检记录】桌面端胶料快检记录保存----------- + @Operation(summary = "胶料快检记录-免密添加") + @PostMapping("/xslmes/mesXslRubberQuickTestRecord/anon/add") + public Result rubberQuickTestRecordAnonAdd(@RequestBody MesXslRubberQuickTestRecord record) { + if (record == null) { + return Result.error("参数不能为空"); + } + if (oConvertUtils.isEmpty(record.getRubberMaterialName())) { + return Result.error("胶料名称不能为空"); + } + List lineList = record.getLineList(); + if (lineList == null || lineList.isEmpty()) { + return Result.error("请维护检验明细"); + } + try { + rubberQuickTestRecordService.saveMain(record, lineList); + stompNotify.publishRubberQuickTestRecordChanged("add", record.getId()); + return Result.OK("添加成功!"); + } catch (Exception e) { + log.error(e.getMessage(), e); + return Result.error(e.getMessage()); + } + } + //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】桌面端胶料快检记录保存----------- + // ─────────────────────────── 车辆私有辅助 ──────────────────────────── private void applyWeightNetAndBillType(MesXslWeightRecord record) { diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestRecordController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestRecordController.java index 4cd5973d..f523cd00 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestRecordController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestRecordController.java @@ -24,6 +24,7 @@ import org.jeecg.modules.system.entity.SysUser; import org.jeecg.modules.system.service.ISysUserService; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService; @@ -163,6 +164,15 @@ public class MesXslRubberQuickTestRecordController return Result.OK(mesXslRubberQuickTestRecordService.selectLinesByRecordId(id)); } + //update-begin---author:jiangxh ---date:2026-06-17 for:【快检记录】查询原始数据明细----------- + @Operation(summary = "MES胶料快检记录-查询原始数据明细") + @GetMapping(value = "/queryRawLineListByRecordId") + public Result> queryRawLineListByRecordId( + @RequestParam(name = "id", required = true) String id) { + return Result.OK(mesXslRubberQuickTestRecordService.selectRawLinesByRecordId(id)); + } + //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】查询原始数据明细----------- + @RequiresPermissions("mes:mes_xsl_rubber_quick_test_record:exportXls") @RequestMapping(value = "/exportXls") public ModelAndView exportXls(HttpServletRequest request, MesXslRubberQuickTestRecord model) { diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestStdController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestStdController.java index a8e3a3ca..4cf6f549 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestStdController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestStdController.java @@ -36,6 +36,7 @@ import org.jeecg.modules.xslmes.service.IMesXslMixerPsCompileService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService; import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService; +import org.jeecg.modules.xslmes.service.MesXslStompNotifyService; import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestStdPage; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -73,6 +74,9 @@ public class MesXslRubberQuickTestStdController @Autowired private IMesXslDeleteReferenceService mesXslDeleteReferenceService; + @Autowired + private MesXslStompNotifyService stompNotify; + @Operation(summary = "MES胶料快检实验标准-分页列表查询") @GetMapping(value = "/list") public Result> queryPageList( @@ -107,6 +111,9 @@ public class MesXslRubberQuickTestStdController log.error(e.getMessage(), e); return Result.error(e.getMessage()); } + //update-begin---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端 STOMP 同步----------- + stompNotify.publishRubberQuickTestStdChanged("add", main.getId()); + //update-end---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端 STOMP 同步----------- return Result.OK("添加成功!"); } @@ -129,6 +136,9 @@ public class MesXslRubberQuickTestStdController log.error(e.getMessage(), e); return Result.error(e.getMessage()); } + //update-begin---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端 STOMP 同步----------- + stompNotify.publishRubberQuickTestStdChanged("edit", main.getId()); + //update-end---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端 STOMP 同步----------- return Result.OK("编辑成功!"); } @@ -142,6 +152,9 @@ public class MesXslRubberQuickTestStdController return Result.error(refErr); } mesXslRubberQuickTestStdService.delMain(id); + //update-begin---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端 STOMP 同步----------- + stompNotify.publishRubberQuickTestStdChanged("delete", id); + //update-end---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端 STOMP 同步----------- return Result.OK("删除成功!"); } @@ -155,6 +168,9 @@ public class MesXslRubberQuickTestStdController return Result.error(refErr); } mesXslRubberQuickTestStdService.delBatchMain(Arrays.asList(ids.split(","))); + //update-begin---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端 STOMP 同步----------- + stompNotify.publishRubberQuickTestStdChanged("batchDelete", ids); + //update-end---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端 STOMP 同步----------- return Result.OK("批量删除成功!"); } @@ -196,6 +212,9 @@ public class MesXslRubberQuickTestStdController .set(MesXslRubberQuickTestStd::getEnableStatus, enableStatus) .update(); if (updated) { + //update-begin---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端 STOMP 同步----------- + stompNotify.publishRubberQuickTestStdChanged("status", id); + //update-end---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端 STOMP 同步----------- return Result.OK("操作成功"); } MesXslRubberQuickTestStd cur = mesXslRubberQuickTestStdService.getById(id); @@ -272,6 +291,18 @@ public class MesXslRubberQuickTestStdController if (!XslMesBizConstants.PS_TYPE_RAW_INSPECT_STD.equals(ps.getPsType())) { return "发行编号须选择类型为原材料检验标准的密炼PS"; } + //update-begin---author:jiangxh ---date:20260617 for:【快检实验标准】发行编号仅允许选择编制状态密炼PS----------- + boolean psCompileIdChanged = true; + if (oConvertUtils.isNotEmpty(excludeId)) { + MesXslRubberQuickTestStd existingStd = mesXslRubberQuickTestStdService.getById(excludeId); + if (existingStd != null && oConvertUtils.isNotEmpty(existingStd.getPsCompileId())) { + psCompileIdChanged = !existingStd.getPsCompileId().equals(main.getPsCompileId()); + } + } + if (psCompileIdChanged && !"compile".equals(ps.getStatus())) { + return "发行编号须选择编制状态的密炼PS"; + } + //update-end---author:jiangxh ---date:20260617 for:【快检实验标准】发行编号仅允许选择编制状态密炼PS----------- main.setIssueNumber(ps.getPsCode()); if (main.getIssueDate() == null && ps.getIssueDate() != null) { main.setIssueDate(ps.getIssueDate()); diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecord.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecord.java index 0668e132..694a3325 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecord.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecord.java @@ -130,4 +130,8 @@ public class MesXslRubberQuickTestRecord implements Serializable { @TableField(exist = false) private List lineList; + + @TableField(exist = false) + @Schema(description = "原始数据明细(试验结果全部检测值)") + private List rawLineList; } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecordRawLine.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecordRawLine.java new file mode 100644 index 00000000..536ed31b --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecordRawLine.java @@ -0,0 +1,72 @@ +package org.jeecg.modules.xslmes.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.jeecg.common.aspect.annotation.Dict; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.springframework.format.annotation.DateTimeFormat; + +/** + * MES 胶料快检记录原始数据明细(试验结果全部检测值) + */ +@Data +@TableName("mes_xsl_rubber_quick_test_record_raw_line") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "MES胶料快检记录原始数据明细") +public class MesXslRubberQuickTestRecordRawLine implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Schema(description = "主表ID mes_xsl_rubber_quick_test_record.id") + private String recordId; + + @Excel(name = "编号", width = 14) + @Schema(description = "试验结果编号(如1_1)") + private String rowNo; + + @Schema(description = "数据点ID") + private String dataPointId; + + @Excel(name = "数据点", width = 18) + private String inspectItem; + + @Excel(name = "下限值", width = 12, type = 10) + private BigDecimal lowerLimit; + + @Excel(name = "上限值", width = 12, type = 10) + private BigDecimal upperLimit; + + @Excel(name = "检测值", width = 12, type = 10) + private BigDecimal inspectValue; + + @Excel(name = "行检验结果", width = 10, dicCode = "xslmes_rubber_quick_test_record_result") + @Dict(dicCode = "xslmes_rubber_quick_test_record_result") + @Schema(description = "行检验结果(1合格0不合格)") + private String rowInspectResult; + + private Integer sortNo; + private String createBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + private String updateBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslRubberQuickTestRecordRawLineMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslRubberQuickTestRecordRawLineMapper.java new file mode 100644 index 00000000..396b4df4 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslRubberQuickTestRecordRawLineMapper.java @@ -0,0 +1,6 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine; + +public interface MesXslRubberQuickTestRecordRawLineMapper extends BaseMapper {} 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 a7edf022..8c5a0858 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 @@ -6,6 +6,7 @@ import java.util.Collection; import java.util.List; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine; import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestRecordBatchFromMaterialVO; public interface IMesXslRubberQuickTestRecordService extends IService { @@ -20,6 +21,8 @@ public interface IMesXslRubberQuickTestRecordService extends IService selectLinesByRecordId(String recordId); + List selectRawLinesByRecordId(String recordId); + String generateRecordNo(MesXslRubberQuickTestRecord context); List batchFromMaterial(MesXslRubberQuickTestRecordBatchFromMaterialVO vo); diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/MesXslStompNotifyService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/MesXslStompNotifyService.java index 72308ef3..6994c8f7 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/MesXslStompNotifyService.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/MesXslStompNotifyService.java @@ -83,6 +83,22 @@ public class MesXslStompNotifyService { } //update-end---author:cursor ---date:20250602 for:【密炼物料皮重策略】桌面端同步----------- + //update-begin---author:jiangxh ---date:2026-06-17 for:【快检记录】桌面端胶料快检记录同步----------- + /** 广播胶料快检记录变更事件到 /topic/sync/mes-rubber-quick-test-records */ + public void publishRubberQuickTestRecordChanged(String action, String recordId) { + publish("/topic/sync/mes-rubber-quick-test-records", "MES_RUBBER_QUICK_TEST_RECORD_CHANGED", + "recordId", recordId, action); + } + //update-end---author:jiangxh ---date:20260525 for:【MES】原材料检验标准密炼PS批准时关联实验标准置已批准----------- + + //update-begin---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端只读同步 STOMP----------- + /** 广播胶料快检实验标准变更事件到 /topic/sync/mes-rubber-quick-test-stds */ + public void publishRubberQuickTestStdChanged(String action, String stdId) { + publish("/topic/sync/mes-rubber-quick-test-stds", "MES_RUBBER_QUICK_TEST_STD_CHANGED", + "stdId", stdId, action); + } + //update-end---author:jiangxh ---date:20260617 for:【快检实验标准】桌面端只读同步 STOMP----------- + // ─────────────────────────── 私有辅助 ──────────────────────────── private void publish(String topic, String cmd, String idKey, String idValue, String action) { 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 40a91d54..c20d1797 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 @@ -20,11 +20,13 @@ import org.jeecg.modules.xslmes.common.XslMesBizConstants; 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.MesXslRubberQuickTestRecordRawLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStdLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType; import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordLineMapper; import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordMapper; +import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordRawLineMapper; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService; @@ -45,6 +47,9 @@ public class MesXslRubberQuickTestRecordServiceImpl @Autowired private MesXslRubberQuickTestRecordLineMapper mesXslRubberQuickTestRecordLineMapper; + @Autowired + private MesXslRubberQuickTestRecordRawLineMapper mesXslRubberQuickTestRecordRawLineMapper; + @Autowired private IMesXslRubberQuickTestStdService mesXslRubberQuickTestStdService; @@ -65,6 +70,9 @@ public class MesXslRubberQuickTestRecordServiceImpl } this.save(main); insertLines(main.getId(), lineList); + //update-begin---author:jiangxh ---date:2026-06-17 for:【快检记录】保存试验结果原始数据明细----------- + insertRawLines(main.getId(), main.getRawLineList()); + //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】保存试验结果原始数据明细----------- } @Override @@ -81,6 +89,12 @@ public class MesXslRubberQuickTestRecordServiceImpl new LambdaQueryWrapper() .eq(MesXslRubberQuickTestRecordLine::getRecordId, main.getId())); insertLines(main.getId(), lineList); + //update-begin---author:jiangxh ---date:2026-06-17 for:【快检记录】更新时同步原始数据明细----------- + mesXslRubberQuickTestRecordRawLineMapper.delete( + new LambdaQueryWrapper() + .eq(MesXslRubberQuickTestRecordRawLine::getRecordId, main.getId())); + insertRawLines(main.getId(), main.getRawLineList()); + //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】更新时同步原始数据明细----------- } private void insertLines(String recordId, List lineList) { @@ -96,11 +110,31 @@ public class MesXslRubberQuickTestRecordServiceImpl } } + //update-begin---author:jiangxh ---date:2026-06-17 for:【快检记录】原始数据明细入库----------- + private void insertRawLines(String recordId, List rawLineList) { + if (CollectionUtils.isEmpty(rawLineList)) { + return; + } + int sort = 0; + for (MesXslRubberQuickTestRecordRawLine line : rawLineList) { + if (line == null) { + continue; + } + line.setId(null); + line.setRecordId(recordId); + line.setSortNo(sort++); + mesXslRubberQuickTestRecordRawLineMapper.insert(line); + } + } + //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】原始数据明细入库----------- + @Override @Transactional(rollbackFor = Exception.class) public void delMain(String id) { mesXslRubberQuickTestRecordLineMapper.delete( new LambdaQueryWrapper().eq(MesXslRubberQuickTestRecordLine::getRecordId, id)); + mesXslRubberQuickTestRecordRawLineMapper.delete( + new LambdaQueryWrapper().eq(MesXslRubberQuickTestRecordRawLine::getRecordId, id)); this.removeById(id); } @@ -120,6 +154,14 @@ public class MesXslRubberQuickTestRecordServiceImpl .orderByAsc(MesXslRubberQuickTestRecordLine::getSortNo)); } + @Override + public List selectRawLinesByRecordId(String recordId) { + return mesXslRubberQuickTestRecordRawLineMapper.selectList( + new LambdaQueryWrapper() + .eq(MesXslRubberQuickTestRecordRawLine::getRecordId, recordId) + .orderByAsc(MesXslRubberQuickTestRecordRawLine::getSortNo)); + } + //update-begin---author:jiangxh ---date:20260528 for:【MES】胶料快检记录单号JL+日期+4位流水自动生成----------- @Override public String generateRecordNo(MesXslRubberQuickTestRecord context) { diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestStdServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestStdServiceImpl.java index 6bfb3673..3c545625 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestStdServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestStdServiceImpl.java @@ -87,6 +87,11 @@ public class MesXslRubberQuickTestStdServiceImpl if (oConvertUtils.isEmpty(main.getAuditStatus())) { main.setAuditStatus("0"); } + //update-begin---author:jiangxh ---date:20260617 for:【快检实验标准】新增时补齐 tenant_id----------- + if (main.getTenantId() == null) { + main.setTenantId(MesXslTenantUtils.resolveTenantId(null)); + } + //update-end---author:jiangxh ---date:20260617 for:【快检实验标准】新增时补齐 tenant_id----------- } private void insertLines(String stdId, List lineList) { diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_151__mes_xsl_rubber_quick_test_record_raw_line.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_151__mes_xsl_rubber_quick_test_record_raw_line.sql new file mode 100644 index 00000000..2355bb4a --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_151__mes_xsl_rubber_quick_test_record_raw_line.sql @@ -0,0 +1,21 @@ +-- MES 胶料快检记录原始数据明细(存储桌面端试验结果全部检测值) +SET NAMES utf8mb4; + +CREATE TABLE IF NOT EXISTS `mes_xsl_rubber_quick_test_record_raw_line` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `record_id` varchar(32) NOT NULL COMMENT '主表 mes_xsl_rubber_quick_test_record.id', + `row_no` varchar(32) DEFAULT NULL COMMENT '试验结果编号(如1_1)', + `data_point_id` varchar(32) DEFAULT NULL COMMENT '数据点ID', + `inspect_item` varchar(128) DEFAULT NULL COMMENT '数据点名称', + `lower_limit` decimal(18,6) DEFAULT NULL COMMENT '下限值', + `upper_limit` decimal(18,6) DEFAULT NULL COMMENT '上限值', + `inspect_value` decimal(18,6) DEFAULT NULL COMMENT '检测值', + `row_inspect_result` varchar(2) DEFAULT NULL COMMENT '行检验结果(字典xslmes_rubber_quick_test_record_result:1合格0不合格)', + `sort_no` int DEFAULT NULL COMMENT '排序号', + `create_by` varchar(32) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(32) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `idx_rubber_quick_test_record_raw_record_id` (`record_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES胶料快检记录原始数据明细'; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_152__mes_xsl_rubber_quick_test_std_tenant_backfill.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_152__mes_xsl_rubber_quick_test_std_tenant_backfill.sql new file mode 100644 index 00000000..bb4ca106 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_152__mes_xsl_rubber_quick_test_std_tenant_backfill.sql @@ -0,0 +1,11 @@ +-- 胶料快检实验标准:补齐 tenant_id 为空的记录(与 MES 默认租户 1002 一致) +-- 说明:桌面端按 tenantId 拉取列表,tenant_id 为 NULL 的记录会被过滤导致条数不一致 + +SET NAMES utf8mb4; + +SET @mes_tenant_id = 1002; + +UPDATE `mes_xsl_rubber_quick_test_std` +SET `tenant_id` = @mes_tenant_id +WHERE `tenant_id` IS NULL + AND (`del_flag` = 0 OR `del_flag` IS NULL); diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslRubberQuickTestStd/components/MesXslRubberQuickTestStdMixerPsSelectModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslRubberQuickTestStd/components/MesXslRubberQuickTestStdMixerPsSelectModal.vue index dd4d551d..145b7021 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslRubberQuickTestStd/components/MesXslRubberQuickTestStdMixerPsSelectModal.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslRubberQuickTestStd/components/MesXslRubberQuickTestStdMixerPsSelectModal.vue @@ -18,6 +18,8 @@ /** 密炼PS类型:原材料检验标准 */ const PS_TYPE_RAW_INSPECT_STD = 'raw_inspect_std'; + /** 密炼PS状态:编制 */ + const COMPILE_STATUS = 'compile'; const selectSearchSchema: FormSchema[] = [ { label: 'PS编码', field: 'psCode', component: 'JInput', colProps: { span: 8 } }, @@ -42,6 +44,7 @@ beforeFetch: (params) => ({ ...params, psType: PS_TYPE_RAW_INSPECT_STD, + status: COMPILE_STATUS, }), rowSelection: { type: 'radio', @@ -85,7 +88,11 @@ } } if (!row?.id) { - createMessage.warning('请选择一条密炼PS'); + createMessage.warning('请选择一条编制状态的密炼PS'); + return; + } + if (row.status && row.status !== COMPILE_STATUS) { + createMessage.warning('仅可选择编制状态的密炼PS'); return; } if (row.psType && row.psType !== PS_TYPE_RAW_INSPECT_STD) { diff --git a/yy-admin-master/YY.Admin.Core/Core/Events/RubberQuickTestStdChangedEvent.cs b/yy-admin-master/YY.Admin.Core/Core/Events/RubberQuickTestStdChangedEvent.cs new file mode 100644 index 00000000..ae862990 --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Core/Events/RubberQuickTestStdChangedEvent.cs @@ -0,0 +1,11 @@ +using Prism.Events; + +namespace YY.Admin.Core.Events; + +public class RubberQuickTestStdChangedPayload +{ + public string Action { get; set; } = string.Empty; + public string? StdId { get; set; } +} + +public class RubberQuickTestStdChangedEvent : PubSubEvent { } diff --git a/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestOperationService.cs b/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestOperationService.cs new file mode 100644 index 00000000..24d82053 --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestOperationService.cs @@ -0,0 +1,13 @@ +using YY.Admin.Core.Entity; + +namespace YY.Admin.Core.Services; + +/// 胶料快检记录操作台:密炼计划筛选、实验标准匹配、记录保存 +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 new file mode 100644 index 00000000..6ce239f3 --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestStdService.cs @@ -0,0 +1,24 @@ +using YY.Admin.Core.Entity; + +namespace YY.Admin.Core.Services; + +/// 胶料快检实验标准(MES 只读同步) +public interface IRubberQuickTestStdService +{ + Task PageAsync( + int pageNo, int pageSize, + string? stdName = null, + string? rubberMaterialName = null, + string? enableStatus = null, + CancellationToken ct = default); + + Task GetByIdAsync(string id, CancellationToken ct = default); + + Task SyncFromRemoteAsync(CancellationToken ct = default); +} + +public record RubberQuickTestStdPageResult( + List Records, + long Total, + int PageNo, + int PageSize); diff --git a/yy-admin-master/YY.Admin.Core/Entity/MesXslMixingProductionPlan.cs b/yy-admin-master/YY.Admin.Core/Entity/MesXslMixingProductionPlan.cs new file mode 100644 index 00000000..2994f4cf --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Entity/MesXslMixingProductionPlan.cs @@ -0,0 +1,28 @@ +namespace YY.Admin.Core.Entity; + +/// 密炼生产计划维护(桌面端快检记录筛选用) +public class MesXslMixingProductionPlan +{ + public string? Id { get; set; } + public int? SortNo { get; set; } + public string? MachineId { get; set; } + public string? MachineName { get; set; } + + public string? MorningPlanId { get; set; } + public string? MorningPlanType { get; set; } + public string? MorningOrderNo { get; set; } + public DateTime? MorningOrderDate { get; set; } + public string? MorningFormulaName { get; set; } + + public string? NoonPlanId { get; set; } + public string? NoonPlanType { get; set; } + public string? NoonOrderNo { get; set; } + public DateTime? NoonOrderDate { get; set; } + public string? NoonFormulaName { get; set; } + + public string? NightPlanId { get; set; } + public string? NightPlanType { get; set; } + public string? NightOrderNo { get; set; } + public DateTime? NightOrderDate { get; set; } + public string? NightFormulaName { get; set; } +} diff --git a/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecord.cs b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecord.cs new file mode 100644 index 00000000..0e39eced --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecord.cs @@ -0,0 +1,24 @@ +namespace YY.Admin.Core.Entity; + +public class MesXslRubberQuickTestRecord +{ + public string? Id { get; set; } + public string? RecordNo { get; set; } + public string? RubberMaterialId { get; set; } + public string? RubberMaterialName { get; set; } + public string? StdId { get; set; } + public string? ProdEquipmentLedgerId { get; set; } + public string? ProdEquipmentName { get; set; } + public DateTime? ProductionDate { get; set; } + public string? TrainNo { get; set; } + public string? WorkShift { get; set; } + public int? InspectTimes { get; set; } + public DateTime? InspectTime { get; set; } + public string? InspectorUserId { get; set; } + public string? InspectorUsername { get; set; } + public string? InspectorRealname { get; set; } + public string? InspectResult { get; set; } + public string? ProductionPlanNo { get; set; } + public List? LineList { get; set; } + public List? RawLineList { get; set; } +} diff --git a/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordLine.cs b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordLine.cs new file mode 100644 index 00000000..2c261889 --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordLine.cs @@ -0,0 +1,13 @@ +namespace YY.Admin.Core.Entity; + +public class MesXslRubberQuickTestRecordLine +{ + public string? Id { get; set; } + public string? RecordId { get; set; } + public string? DataPointId { get; set; } + public string? InspectItem { get; set; } + public decimal? LowerLimit { get; set; } + public decimal? InspectValue { get; set; } + public decimal? UpperLimit { get; set; } + public int? SortNo { get; set; } +} diff --git a/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordRawLine.cs b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordRawLine.cs new file mode 100644 index 00000000..3c3bbd42 --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordRawLine.cs @@ -0,0 +1,17 @@ +namespace YY.Admin.Core.Entity; + +/// MES 胶料快检记录原始数据明细 +public class MesXslRubberQuickTestRecordRawLine +{ + public string? Id { get; set; } + public string? RecordId { get; set; } + public string? RowNo { get; set; } + public string? DataPointId { get; set; } + public string? InspectItem { get; set; } + public decimal? LowerLimit { get; set; } + public decimal? UpperLimit { get; set; } + public decimal? InspectValue { get; set; } + /// 行检验结果:1合格 0不合格 + public string? RowInspectResult { get; set; } + public int? SortNo { get; set; } +} diff --git a/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStd.cs b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStd.cs new file mode 100644 index 00000000..7b4d775b --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStd.cs @@ -0,0 +1,32 @@ +using System; + +namespace YY.Admin.Core.Entity; + +/// MES 胶料快检实验标准主表(桌面端只读同步) +public class MesXslRubberQuickTestStd +{ + public string? Id { get; set; } + public string? StdName { get; set; } + public string? TestMethodId { get; set; } + public string? TestMethodName { get; set; } + public string? MixerType { get; set; } + public string? RubberMaterialId { get; set; } + public string? RubberMaterialName { get; set; } + public string? PsCompileId { get; set; } + public string? IssueNumber { get; set; } + public DateTime? IssueDate { get; set; } + public string? IssueDeptId { get; set; } + public string? IssueDeptName { get; set; } + public string? EnableStatus { get; set; } + public string? AuditStatus { get; set; } + public int? TenantId { get; set; } + public string? SysOrgCode { get; set; } + public string? CreateBy { get; set; } + public DateTime? CreateTime { get; set; } + public string? UpdateBy { get; set; } + public DateTime? UpdateTime { get; set; } + public List? LineList { get; set; } + + public string EnableStatusText => EnableStatus == "0" ? "已停用" : EnableStatus == "1" ? "使用中" : EnableStatus ?? string.Empty; + public string AuditStatusText => AuditStatus == "1" ? "已批准" : AuditStatus == "0" ? "草稿" : AuditStatus ?? string.Empty; +} diff --git a/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStdLine.cs b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStdLine.cs new file mode 100644 index 00000000..54ed3430 --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestStdLine.cs @@ -0,0 +1,15 @@ +namespace YY.Admin.Core.Entity; + +public class MesXslRubberQuickTestStdLine +{ + public string? Id { get; set; } + public string? StdId { get; set; } + public string? DataPointId { get; set; } + public string? PointName { get; set; } + public decimal? LowerLimit { get; set; } + public decimal? UpperLimit { get; set; } + public decimal? LowerWarn { get; set; } + public decimal? UpperWarn { get; set; } + public decimal? TargetValue { get; set; } + public int? SortNo { 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 dfb1c1d5..674134e3 100644 --- a/yy-admin-master/YY.Admin.Core/SeedData/SysMenuSeedData.cs +++ b/yy-admin-master/YY.Admin.Core/SeedData/SysMenuSeedData.cs @@ -48,6 +48,10 @@ 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 }, #endregion diff --git a/yy-admin-master/YY.Admin.Core/SeedData/SysTenantMenuSeedData.cs b/yy-admin-master/YY.Admin.Core/SeedData/SysTenantMenuSeedData.cs index b3b9d362..52f35768 100644 --- a/yy-admin-master/YY.Admin.Core/SeedData/SysTenantMenuSeedData.cs +++ b/yy-admin-master/YY.Admin.Core/SeedData/SysTenantMenuSeedData.cs @@ -32,6 +32,8 @@ public class SysTenantMenuSeedData : ISqlSugarEntitySeedData new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010901}, new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011001}, new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011101}, + new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011201}, + new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011301}, new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012101}, new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012111}, new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012121}, diff --git a/yy-admin-master/YY.Admin.Services/Service/RubberQuickTest/RubberQuickTestOperationService.cs b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTest/RubberQuickTestOperationService.cs new file mode 100644 index 00000000..d8c2cc94 --- /dev/null +++ b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTest/RubberQuickTestOperationService.cs @@ -0,0 +1,117 @@ +using Microsoft.Extensions.Configuration; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using YY.Admin.Core; +using YY.Admin.Core.Entity; +using YY.Admin.Core.Services; + +namespace YY.Admin.Services.Service.RubberQuickTest; + +public class RubberQuickTestOperationService : IRubberQuickTestOperationService, ISingletonDependency +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly IConfiguration _configuration; + private readonly INetworkMonitor _networkMonitor; + private readonly ILoggerService _logger; + + private static readonly JsonSerializerOptions _jsonOpts = new() + { + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; + + public RubberQuickTestOperationService( + IHttpClientFactory httpClientFactory, + IConfiguration configuration, + INetworkMonitor networkMonitor, + ILoggerService logger) + { + _httpClientFactory = httpClientFactory; + _configuration = configuration; + _networkMonitor = networkMonitor; + _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) + { + if (!_networkMonitor.IsOnline) + throw new InvalidOperationException("网络未连接,无法加载密炼生产计划"); + + var result = new List(); + int pageNo = 1; + const int pageSize = 500; + while (true) + { + var url = $"{BaseUrl}/xslmes/mesXslMixingProductionPlan/anon/list?pageNo={pageNo}&pageSize={pageSize}&tenantId={DefaultTenantId}"; + using var client = _httpClientFactory.CreateClient("JeecgApi"); + var resp = await client.GetAsync(url, ct).ConfigureAwait(false); + resp.EnsureSuccessStatusCode(); + var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false); + using var doc = JsonDocument.Parse(json); + if (!doc.RootElement.TryGetProperty("result", out var resultEl)) break; + if (resultEl.TryGetProperty("records", out var recordsEl)) + { + var page = recordsEl.Deserialize>(_jsonOpts); + if (page != null) result.AddRange(page); + } + long total = 0; + if (resultEl.TryGetProperty("total", out var totalEl)) total = totalEl.GetInt64(); + if (result.Count >= total || (resultEl.TryGetProperty("records", out var r2) && r2.GetArrayLength() < pageSize)) break; + pageNo++; + } + + _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("网络未连接,无法保存快检记录"); + + var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestRecord/anon/add"; + using var client = _httpClientFactory.CreateClient("JeecgApi"); + var body = JsonSerializer.Serialize(record, _jsonOpts); + using var content = new StringContent(body, Encoding.UTF8, "application/json"); + var resp = await client.PostAsync(url, content, 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() : "保存失败"; + throw new InvalidOperationException(msg ?? "保存失败"); + } + _logger.Information($"[快检记录] 保存成功 recordNo={record.RecordNo}"); + return doc.RootElement.TryGetProperty("message", out var m) ? m.GetString() : "保存成功"; + } +} diff --git a/yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdService.cs b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdService.cs new file mode 100644 index 00000000..1890e2d1 --- /dev/null +++ b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdService.cs @@ -0,0 +1,302 @@ +using Microsoft.Extensions.Configuration; +using Prism.Events; +using System.IO; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Web; +using YY.Admin.Core; +using YY.Admin.Core.Entity; +using YY.Admin.Core.Events; +using YY.Admin.Core.Services; + +namespace YY.Admin.Services.Service.RubberQuickTestStd; + +/// 胶料快检实验标准:MES 只读拉取 + 本地缓存,断网读缓存,联网刷新 +public class RubberQuickTestStdService : IRubberQuickTestStdService, ISingletonDependency +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly IConfiguration _configuration; + private readonly INetworkMonitor _networkMonitor; + private readonly IEventAggregator _eventAggregator; + private readonly ILoggerService _logger; + private readonly SemaphoreSlim _syncLock = new(1, 1); + private readonly object _cacheLock = new(); + private readonly string _cacheFilePath; + private List _localCache = new(); + + private static readonly JsonSerializerOptions _jsonOpts = new() + { + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = { new NullableDateTimeJsonConverter() } + }; + + public RubberQuickTestStdService( + IHttpClientFactory httpClientFactory, + IConfiguration configuration, + INetworkMonitor networkMonitor, + IEventAggregator eventAggregator, + ILoggerService logger) + { + _httpClientFactory = httpClientFactory; + _configuration = configuration; + _networkMonitor = networkMonitor; + _eventAggregator = eventAggregator; + _logger = logger; + + var appDataDir = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "YY.Admin", "sync-cache"); + Directory.CreateDirectory(appDataDir); + _cacheFilePath = Path.Combine(appDataDir, "mes-xsl-rubber-quick-test-std-cache.json"); + + LoadCacheFromDisk(); + _logger.Information($"[快检实验标准] 服务初始化,缓存={_localCache.Count},在线={_networkMonitor.IsOnline}"); + + _networkMonitor.StatusChanged += OnNetworkStatusChanged; + if (_networkMonitor.IsOnline) + _ = Task.Run(() => SyncFromRemoteAsync(CancellationToken.None)); + } + + private string BaseUrl => (_configuration.GetValue("JeecgIntegration:BaseUrl") ?? "http://localhost:8080/jeecg-boot").TrimEnd('/'); + private int DefaultTenantId => (int?)_configuration.GetValue("JeecgIntegration:DefaultTenantId") ?? 1002; + private HttpClient CreateClient() => _httpClientFactory.CreateClient("JeecgApi"); + + public async Task PageAsync( + int pageNo, int pageSize, + string? stdName = null, + string? rubberMaterialName = null, + string? enableStatus = null, + CancellationToken ct = default) + { + if (_networkMonitor.IsOnline) + { + try + { + await SyncFromRemoteAsync(ct).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.Warning($"[快检实验标准] 列表拉取失败,使用本地缓存:{ex.Message}"); + } + } + + List source; + lock (_cacheLock) + source = _localCache.Select(CloneMain).ToList(); + + var filtered = ApplyFilters(source, stdName, rubberMaterialName, enableStatus); + var total = filtered.Count; + var records = filtered + .Skip(Math.Max(0, (pageNo - 1) * pageSize)) + .Take(pageSize) + .ToList(); + return new RubberQuickTestStdPageResult(records, total, pageNo, pageSize); + } + + public async Task GetByIdAsync(string id, CancellationToken ct = default) + { + if (string.IsNullOrWhiteSpace(id)) return null; + + if (_networkMonitor.IsOnline) + { + try + { + var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestStd/anon/queryById?id={Uri.EscapeDataString(id)}"; + using var client = CreateClient(); + var resp = await client.GetAsync(url, ct).ConfigureAwait(false); + 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)) + { + var entity = resultEl.Deserialize(_jsonOpts); + if (entity != null) + { + UpsertLocalCacheMain(entity); + return CloneMain(entity); + } + } + } + } + catch (Exception ex) + { + _logger.Warning($"[快检实验标准] 详情拉取失败 id={id},回退缓存:{ex.Message}"); + } + } + + lock (_cacheLock) + { + var found = _localCache.FirstOrDefault(x => string.Equals(x.Id, id, StringComparison.OrdinalIgnoreCase)); + return found != null ? CloneMain(found) : null; + } + } + + public async Task SyncFromRemoteAsync(CancellationToken ct = default) + { + await _syncLock.WaitAsync(ct).ConfigureAwait(false); + + try + { + if (!_networkMonitor.IsOnline) + return; + + var query = HttpUtility.ParseQueryString(string.Empty); + query["pageNo"] = "1"; + query["pageSize"] = "10000"; + query["tenantId"] = DefaultTenantId.ToString(); + var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestStd/anon/list?{query}"; + + using var client = CreateClient(); + var resp = await client.GetAsync(url, ct).ConfigureAwait(false); + resp.EnsureSuccessStatusCode(); + + var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false); + using var doc = JsonDocument.Parse(json); + var records = doc.RootElement.GetProperty("result").GetProperty("records") + .Deserialize>(_jsonOpts) ?? new(); + + lock (_cacheLock) + { + _localCache = records.Select(CloneMain).ToList(); + SaveCacheToDiskUnsafe(); + } + _logger.Information($"[快检实验标准] 同步完成 count={records.Count}"); + } + catch (Exception ex) + { + _logger.Warning($"[快检实验标准] 远程同步失败:{ex.Message}"); + } + finally + { + _syncLock.Release(); + } + } + + private void OnNetworkStatusChanged(bool isOnline) + { + if (!isOnline) return; + _ = Task.Run(async () => + { + await SyncFromRemoteAsync(CancellationToken.None).ConfigureAwait(false); + _eventAggregator.GetEvent() + .Publish(new RubberQuickTestStdChangedPayload { Action = "reconnect" }); + }); + } + + private static List ApplyFilters( + List source, + string? stdName, + string? rubberMaterialName, + string? enableStatus) + { + IEnumerable q = source; + if (!string.IsNullOrWhiteSpace(stdName)) + q = q.Where(x => (x.StdName ?? "").Contains(stdName.Trim(), StringComparison.OrdinalIgnoreCase)); + if (!string.IsNullOrWhiteSpace(rubberMaterialName)) + q = q.Where(x => (x.RubberMaterialName ?? "").Contains(rubberMaterialName.Trim(), StringComparison.OrdinalIgnoreCase)); + if (!string.IsNullOrWhiteSpace(enableStatus)) + q = q.Where(x => string.Equals(x.EnableStatus, enableStatus.Trim(), StringComparison.OrdinalIgnoreCase)); + return q.OrderByDescending(x => x.CreateTime ?? DateTime.MinValue).ToList(); + } + + private void UpsertLocalCacheMain(MesXslRubberQuickTestStd entity) + { + if (string.IsNullOrWhiteSpace(entity.Id)) return; + lock (_cacheLock) + { + var idx = _localCache.FindIndex(x => string.Equals(x.Id, entity.Id, StringComparison.OrdinalIgnoreCase)); + var copy = CloneMain(entity); + if (idx >= 0) _localCache[idx] = copy; + else _localCache.Insert(0, copy); + SaveCacheToDiskUnsafe(); + } + } + + private void LoadCacheFromDisk() + { + try + { + if (!File.Exists(_cacheFilePath)) return; + _localCache = JsonSerializer.Deserialize>( + File.ReadAllText(_cacheFilePath), _jsonOpts) ?? new(); + } + catch + { + _localCache = new(); + } + } + + private void SaveCacheToDiskUnsafe() => + File.WriteAllText(_cacheFilePath, JsonSerializer.Serialize(_localCache, _jsonOpts)); + + private static MesXslRubberQuickTestStd CloneMain(MesXslRubberQuickTestStd x) => new() + { + Id = x.Id, + StdName = x.StdName, + TestMethodId = x.TestMethodId, + TestMethodName = x.TestMethodName, + MixerType = x.MixerType, + RubberMaterialId = x.RubberMaterialId, + RubberMaterialName = x.RubberMaterialName, + PsCompileId = x.PsCompileId, + IssueNumber = x.IssueNumber, + IssueDate = x.IssueDate, + IssueDeptId = x.IssueDeptId, + IssueDeptName = x.IssueDeptName, + EnableStatus = x.EnableStatus, + AuditStatus = x.AuditStatus, + TenantId = x.TenantId, + SysOrgCode = x.SysOrgCode, + CreateBy = x.CreateBy, + CreateTime = x.CreateTime, + UpdateBy = x.UpdateBy, + UpdateTime = x.UpdateTime, + LineList = x.LineList?.Select(l => new MesXslRubberQuickTestStdLine + { + Id = l.Id, + StdId = l.StdId, + DataPointId = l.DataPointId, + PointName = l.PointName, + LowerLimit = l.LowerLimit, + UpperLimit = l.UpperLimit, + LowerWarn = l.LowerWarn, + UpperWarn = l.UpperWarn, + TargetValue = l.TargetValue, + SortNo = l.SortNo + }).ToList() + }; + + private sealed class NullableDateTimeJsonConverter : JsonConverter + { + private static readonly string[] Formats = + [ + "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.fff", + "yyyy-MM-ddTHH:mm:ss", "yyyy-MM-ddTHH:mm:ss.fff", + "yyyy-MM-ddTHH:mm:ssZ", "yyyy-MM-ddTHH:mm:ss.fffZ", + "yyyy-MM-dd" + ]; + + public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) return null; + if (reader.TokenType == JsonTokenType.String) + { + var raw = reader.GetString(); + if (string.IsNullOrWhiteSpace(raw)) return null; + if (DateTime.TryParseExact(raw, Formats, System.Globalization.CultureInfo.InvariantCulture, + System.Globalization.DateTimeStyles.AssumeLocal, out var dt)) return dt; + if (DateTime.TryParse(raw, out var fb)) return fb; + } + throw new JsonException($"无法转换为 DateTime?,token={reader.TokenType}"); + } + + public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) + { + if (value.HasValue) writer.WriteStringValue(value.Value.ToString("yyyy-MM-dd HH:mm:ss")); + else writer.WriteNullValue(); + } + } +} diff --git a/yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdSyncCoordinator.cs b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdSyncCoordinator.cs new file mode 100644 index 00000000..4b62b365 --- /dev/null +++ b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdSyncCoordinator.cs @@ -0,0 +1,73 @@ +using Prism.Events; +using System.Text.Json; +using YY.Admin.Core; +using YY.Admin.Core.Events; +using YY.Admin.Core.Events; + +namespace YY.Admin.Services.Service.RubberQuickTestStd; + +public class RubberQuickTestStdSyncCoordinator : ISingletonDependency +{ + private readonly IEventAggregator _eventAggregator; + private readonly ILoggerService _logger; + + public RubberQuickTestStdSyncCoordinator( + IEventAggregator eventAggregator, + SyncPollManager pollManager, + ILoggerService logger) + { + _eventAggregator = eventAggregator; + _logger = logger; + + _eventAggregator.GetEvent() + .Subscribe(OnRemoteCommand, ThreadOption.BackgroundThread); + _eventAggregator.GetEvent() + .Subscribe(OnNetworkStatusChanged, ThreadOption.BackgroundThread); + + pollManager.Register("胶料快检实验标准", () => + { + _eventAggregator.GetEvent() + .Publish(new RubberQuickTestStdChangedPayload { Action = "poll" }); + return Task.CompletedTask; + }); + + _logger.Information("[快检实验标准] RubberQuickTestStdSyncCoordinator 已启动"); + } + + private void OnNetworkStatusChanged(NetworkStatusChangedPayload payload) + { + if (!payload.IsOnline) return; + _logger.Information("[快检实验标准] 网络恢复,触发补偿刷新"); + _eventAggregator.GetEvent() + .Publish(new RubberQuickTestStdChangedPayload { Action = "reconnect" }); + } + + private void OnRemoteCommand(RemoteCommandPayload payload) + { + try + { + var json = payload.CommandJson ?? string.Empty; + if (string.IsNullOrWhiteSpace(json)) return; + + using var doc = JsonDocument.Parse(json); + if (!doc.RootElement.TryGetProperty("cmd", out var cmdEl)) return; + if (!cmdEl.GetString()?.Equals("MES_RUBBER_QUICK_TEST_STD_CHANGED", StringComparison.OrdinalIgnoreCase) ?? true) + return; + + doc.RootElement.TryGetProperty("action", out var actionEl); + doc.RootElement.TryGetProperty("stdId", out var idEl); + + var changed = new RubberQuickTestStdChangedPayload + { + Action = actionEl.GetString() ?? string.Empty, + StdId = idEl.ValueKind == JsonValueKind.String ? idEl.GetString() : null + }; + _logger.Information($"[快检实验标准] STOMP action={changed.Action}, stdId={changed.StdId}"); + _eventAggregator.GetEvent().Publish(changed); + } + catch (Exception ex) + { + _logger.Warning($"[快检实验标准] 处理 STOMP 命令失败:{ex.Message}"); + } + } +} diff --git a/yy-admin-master/YY.Admin/Infrastructure/Hubs/StompWebSocketService.cs b/yy-admin-master/YY.Admin/Infrastructure/Hubs/StompWebSocketService.cs index b29175a3..7780f1a3 100644 --- a/yy-admin-master/YY.Admin/Infrastructure/Hubs/StompWebSocketService.cs +++ b/yy-admin-master/YY.Admin/Infrastructure/Hubs/StompWebSocketService.cs @@ -174,6 +174,10 @@ public class StompWebSocketService : ISignalRService await SendFrameAsync( BuildSubscribeFrame("sub-print-biz-binds", "/topic/sync/print-biz-binds"), cancellationToken).ConfigureAwait(false); + // 胶料快检实验标准变更:订阅 /topic/sync/mes-rubber-quick-test-stds + await SendFrameAsync( + BuildSubscribeFrame("sub-mes-rubber-quick-test-stds", "/topic/sync/mes-rubber-quick-test-stds"), + cancellationToken).ConfigureAwait(false); // 订阅服务端 PONG 回复(应用层假在线检测) await SendFrameAsync( diff --git a/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs b/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs index 0f0b8b9d..f7bf38dd 100644 --- a/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs +++ b/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs @@ -18,6 +18,8 @@ using YY.Admin.Views.WarehouseArea; using YY.Admin.Views.RawMaterialEntry; using YY.Admin.Views.Print; using YY.Admin.Views.MixerMaterialTareStrategy; +using YY.Admin.Views.RubberQuickTest; +using YY.Admin.Views.RubberQuickTestStd; namespace YY.Admin { @@ -95,6 +97,10 @@ namespace YY.Admin containerRegistry.RegisterForNavigation(); // 密炼物料皮重策略 containerRegistry.RegisterForNavigation(); + // 快检记录操作台 + containerRegistry.RegisterForNavigation(); + // 胶料快检实验标准(只读) + containerRegistry.RegisterForNavigation(); // 打印设置 containerRegistry.RegisterForNavigation(); // 打印模板列表 diff --git a/yy-admin-master/YY.Admin/Module/SyncModule.cs b/yy-admin-master/YY.Admin/Module/SyncModule.cs index 114b9cee..5e3de7f3 100644 --- a/yy-admin-master/YY.Admin/Module/SyncModule.cs +++ b/yy-admin-master/YY.Admin/Module/SyncModule.cs @@ -27,6 +27,8 @@ using YY.Admin.Services.Service.Warehouse; using YY.Admin.Services.Service.WarehouseArea; using YY.Admin.Services.Service.WeightRecord; using YY.Admin.Services.Service.Print; +using YY.Admin.Services.Service.RubberQuickTest; +using YY.Admin.Services.Service.RubberQuickTestStd; namespace YY.Admin.Module; @@ -86,6 +88,13 @@ public class SyncModule : IModule containerRegistry.RegisterSingleton(); containerRegistry.RegisterSingleton(); + // 胶料快检记录操作台 + containerRegistry.RegisterSingleton(); + + // 胶料快检实验标准(MES 只读同步) + containerRegistry.RegisterSingleton(); + containerRegistry.RegisterSingleton(); + var serviceCollection = new ServiceCollection(); serviceCollection.AddTransient(); serviceCollection.AddHttpClient("JeecgApi", (sp, client) => @@ -156,6 +165,8 @@ public class SyncModule : IModule // 强制实例化打印模板同步协调器 _ = containerProvider.Resolve(); _ = containerProvider.Resolve(); + // 胶料快检实验标准只读同步协调器 + _ = containerProvider.Resolve(); } private static IAsyncPolicy GetRetryPolicy() diff --git a/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs index 6877c934..a77d596e 100644 --- a/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs +++ b/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs @@ -152,6 +152,16 @@ namespace YY.Admin.ViewModels.Control ["/xslmes/mesXslMixerMaterialTareStrategy"] = "MixerMaterialTareStrategyListView", ["mesXslMixerMaterialTareStrategy"] = "MixerMaterialTareStrategyListView", + // 已实现页面:快检记录操作台 + ["RubberQuickTestOperationView"] = "RubberQuickTestOperationView", + ["/xslmes/rubberQuickTestOperation"] = "RubberQuickTestOperationView", + ["rubberQuickTestOperation"] = "RubberQuickTestOperationView", + + // 已实现页面:胶料快检实验标准(只读) + ["RubberQuickTestStdListView"] = "RubberQuickTestStdListView", + ["/xslmes/mesXslRubberQuickTestStd"] = "RubberQuickTestStdListView", + ["mesXslRubberQuickTestStd"] = "RubberQuickTestStdListView", + // 已实现页面:打印设置 ["PrintSettingsView"] = "PrintSettingsView", ["/system/printSettings"] = "PrintSettingsView", diff --git a/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs new file mode 100644 index 00000000..115cf95a --- /dev/null +++ b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs @@ -0,0 +1,755 @@ +using HandyControl.Controls; +using LiveChartsCore; +using LiveChartsCore.SkiaSharpView; +using LiveChartsCore.SkiaSharpView.Painting; +using Prism.Mvvm; +using SkiaSharp; +using System.Collections.ObjectModel; +using YY.Admin.Core; +using YY.Admin.Core.Entity; +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 DisplayText => string.IsNullOrWhiteSpace(OrderNo) + ? FormulaName ?? string.Empty + : $"{OrderNo} | {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; + 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 +public class RubberQuickTestOperationViewModel : BaseViewModel +{ + private readonly IRubberQuickTestOperationService _operationService; + private readonly Random _rnd = new(); + private List _allPlans = new(); + private List _allShiftOptions = new(); + private MesXslRubberQuickTestStd? _currentStd; + private const int ChartPointCount = 5; + + public event Action? InspectColumnsChanged; + + public RubberQuickTestOperationViewModel( + IRubberQuickTestOperationService operationService, + IContainerExtension container, + IRegionManager regionManager) : base(container, regionManager) + { + _operationService = operationService; + + _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()); + 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 } + }; + TorqueSeries = new ObservableCollection + { + new LineSeries { Name = "S'(dNm)", Values = TorqueValues, GeometrySize = 4, LineSmoothness = 0.3 } + }; + + FillRandomChartData(); + _ = LoadPlansAsync(); + } + + /// 中间库未接入时的曲线演示说明 + 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 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 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(); + } + } + + private string? _selectedMachine; + public string? SelectedMachine + { + get => _selectedMachine; + set + { + if (!SetProperty(ref _selectedMachine, value)) return; + RefreshShiftOptions(); + ClearPlanSelection(); + } + } + + private WorkShiftOption? _selectedShift; + public WorkShiftOption? SelectedShift + { + get => _selectedShift; + set + { + if (!SetProperty(ref _selectedShift, value)) return; + RefreshPlanOptions(); + ClearPlanSelection(); + } + } + + private MixingPlanShiftOption? _selectedPlan; + public MixingPlanShiftOption? SelectedPlan + { + get => _selectedPlan; + set + { + if (!SetProperty(ref _selectedPlan, value)) return; + ApplySelectedPlan(); + } + } + + public string? ProductionOrderNo => _selectedPlan?.OrderNo; + public string? MachineName => _selectedPlan?.MachineName ?? SelectedMachine; + public string? WorkShiftDisplay => SelectedShift?.Name ?? string.Empty; + public string? RubberMaterialName => _selectedPlan?.FormulaName; + + private string? _trainNo; + public string? TrainNo + { + get => _trainNo; + set => SetProperty(ref _trainNo, value); + } + + 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() + { + IsLoading = true; + try + { + _allPlans = await _operationService.GetMixingProductionPlansAsync(); + BuildAllShiftOptions(); + RefreshMachineOptions(); + Growl.Success("密炼生产计划已刷新"); + } + catch (Exception ex) + { + Growl.Error($"加载密炼生产计划失败:{ex.Message}"); + } + finally + { + IsLoading = false; + } + } + + private void BuildAllShiftOptions() + { + _allShiftOptions.Clear(); + foreach (var row in _allPlans) + { + AddShiftOption(row, "morning", "1", "早班", row.MorningPlanId, row.MorningOrderDate, row.MorningOrderNo, row.MorningFormulaName); + AddShiftOption(row, "noon", "2", "中班", row.NoonPlanId, row.NoonOrderDate, row.NoonOrderNo, row.NoonFormulaName); + AddShiftOption(row, "night", "3", "晚班", row.NightPlanId, row.NightOrderDate, row.NightOrderNo, row.NightFormulaName); + } + } + + private void AddShiftOption( + MesXslMixingProductionPlan row, string shiftKey, string shiftCode, string shiftName, + string? planId, DateTime? orderDate, string? orderNo, string? formulaName) + { + if (string.IsNullOrWhiteSpace(planId) || string.IsNullOrWhiteSpace(orderNo)) return; + _allShiftOptions.Add(new MixingPlanShiftOption + { + PlanRowId = row.Id ?? string.Empty, + MachineId = row.MachineId, + MachineName = row.MachineName, + ShiftKey = shiftKey, + ShiftCode = shiftCode, + ShiftName = shiftName, + OrderDate = orderDate, + PlanId = planId, + OrderNo = orderNo, + FormulaName = formulaName + }); + } + + private IEnumerable FilteredByDate => + _allShiftOptions.Where(o => o.OrderDate?.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) + .Select(g => g.First()) + .OrderBy(o => o.ShiftCode); + foreach (var s in shifts) + ShiftOptions.Add(new WorkShiftOption(s.ShiftCode, s.ShiftName)); + 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 + .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)) + SelectedPlan = null; + if (SelectedPlan == null && PlanOptions.Count > 0) + SelectedPlan = PlanOptions[0]; + } + + private void ClearPlanSelection() + { + _selectedPlan = null; + RaisePropertyChanged(nameof(SelectedPlan)); + RaisePropertyChanged(nameof(ProductionOrderNo)); + RaisePropertyChanged(nameof(MachineName)); + RaisePropertyChanged(nameof(WorkShiftDisplay)); + RaisePropertyChanged(nameof(RubberMaterialName)); + ClearStdAndResults(); + } + + private void ApplySelectedPlan() + { + RaisePropertyChanged(nameof(ProductionOrderNo)); + RaisePropertyChanged(nameof(MachineName)); + RaisePropertyChanged(nameof(WorkShiftDisplay)); + RaisePropertyChanged(nameof(RubberMaterialName)); + _ = LoadStdAsync(); + } + + private async Task LoadStdAsync() + { + DataPointColumns.Clear(); + InspectRows.Clear(); + _currentStd = null; + InspectColumnsChanged?.Invoke(); + + 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; + } + } + + private void ClearStdAndResults() + { + DataPointColumns.Clear(); + InspectRows.Clear(); + _currentStd = null; + InspectColumnsChanged?.Invoke(); + } + + /// 打开页面或中间库无数据时填充曲线演示数据(5 点对应 0~2min) + private void FillRandomChartData() + { + UpperTempValues.Clear(); + LowerTempValues.Clear(); + TorqueValues.Clear(); + + 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)); + } + + UpperMoldTemp = UpperTempValues[^1]; + LowerMoldTemp = LowerTempValues[^1]; + TorqueS = TorqueValues[^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(); + row.Cells.Add(cell); + } + row.RecalculateResult(); + InspectRows.Add(row); + SaveCommand.RaiseCanExecuteChanged(); + } + + private void RemoveInspectRow(QuickTestInspectRowViewModel? row) + { + if (row == null) return; + InspectRows.Remove(row); + SelectedInspectRow = null; + SaveCommand.RaiseCanExecuteChanged(); + } + + private async Task SaveAsync() + { + if (string.IsNullOrWhiteSpace(TrainNo)) + { + Growl.Warning("请填写车次"); + return; + } + if (string.IsNullOrWhiteSpace(ProductionOrderNo)) + { + Growl.Warning("请选择密炼计划以带出生产订单号"); + return; + } + if (string.IsNullOrWhiteSpace(RubberMaterialName)) + { + Growl.Warning("请先选择密炼计划以带出胶料名称"); + return; + } + if (_currentStd == null) + { + 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"); + 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) + { + if (!rows.Any()) + return "0"; + return rows.Any(r => r.InspectResultCode != "1") ? "0" : "1"; + } + + 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) + }; + + 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; + + 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 + { + Name = "时间(min)", + MinLimit = 0, + MaxLimit = 2, + Labels = new[] { "0", "0.5", "1", "1.5", "2" }, + LabelsPaint = new SolidColorPaint(SKColors.Gray), + NamePaint = new SolidColorPaint(SKColors.Gray) + } + }; + + private static Axis[] BuildTempYAxis() => new[] + { + new Axis + { + Name = "温度(℃)", + MinLimit = 189, + MaxLimit = 201, + Labeler = v => v switch + { + 189 => "189", + 192 => "192", + 195 => "195", + 198 => "198", + 201 => "201", + _ => string.Empty + }, + LabelsPaint = new SolidColorPaint(SKColors.Gray), + NamePaint = new SolidColorPaint(SKColors.Gray) + } + }; + + 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 + }, + 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) + { + Code = code; + Name = name; + } + + public string Code { get; } + public string Name { get; } +} diff --git a/yy-admin-master/YY.Admin/ViewModels/RubberQuickTestStd/RubberQuickTestStdDetailDialogViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTestStd/RubberQuickTestStdDetailDialogViewModel.cs new file mode 100644 index 00000000..567e297e --- /dev/null +++ b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTestStd/RubberQuickTestStdDetailDialogViewModel.cs @@ -0,0 +1,40 @@ +using HandyControl.Tools.Extension; +using Prism.Commands; +using System.Collections.ObjectModel; +using YY.Admin.Core.Entity; +using YY.Admin.ViewModels; + +namespace YY.Admin.ViewModels.RubberQuickTestStd; + +public class RubberQuickTestStdDetailDialogViewModel : BaseViewModel, IDialogResultable +{ + private MesXslRubberQuickTestStd? _std; + public MesXslRubberQuickTestStd? Std + { + get => _std; + private set => SetProperty(ref _std, value); + } + + public ObservableCollection Lines { get; } = new(); + + private bool _result; + public bool Result { get => _result; set => SetProperty(ref _result, value); } + public Action? CloseAction { get; set; } + + public RubberQuickTestStdDetailDialogViewModel( + IContainerExtension container, + IRegionManager regionManager) : base(container, regionManager) + { + CloseCommand = new DelegateCommand(() => CloseAction?.Invoke()); + } + + public DelegateCommand CloseCommand { get; } + + public void Initialize(MesXslRubberQuickTestStd std) + { + Std = std; + Lines.Clear(); + foreach (var line in std.LineList ?? []) + Lines.Add(line); + } +} diff --git a/yy-admin-master/YY.Admin/ViewModels/RubberQuickTestStd/RubberQuickTestStdListViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTestStd/RubberQuickTestStdListViewModel.cs new file mode 100644 index 00000000..1ef5e1c1 --- /dev/null +++ b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTestStd/RubberQuickTestStdListViewModel.cs @@ -0,0 +1,166 @@ +using HandyControl.Controls; +using HandyControl.Tools.Extension; +using Prism.Events; +using System.Collections.ObjectModel; +using System.Diagnostics; +using YY.Admin.Core; +using YY.Admin.Core.Entity; +using YY.Admin.Core.Events; +using YY.Admin.Core.Helper; +using YY.Admin.Core.Services; +using YY.Admin.Services.Service; +using YY.Admin.Views.RubberQuickTestStd; + +namespace YY.Admin.ViewModels.RubberQuickTestStd; + +public class RubberQuickTestStdListViewModel : BaseViewModel +{ + private readonly IRubberQuickTestStdService _stdService; + private readonly IJeecgDictSyncService _dictSyncService; + private SubscriptionToken? _changedToken; + + private ObservableCollection _items = new(); + public ObservableCollection Items + { + get => _items; + set => SetProperty(ref _items, value); + } + + private long _total; + public long Total { get => _total; set => SetProperty(ref _total, value); } + + private int _pageNo = 1; + public int PageNo { get => _pageNo; set => SetProperty(ref _pageNo, value); } + + private int _pageSize = 20; + public int PageSize { get => _pageSize; set => SetProperty(ref _pageSize, value); } + + private string? _filterStdName; + public string? FilterStdName { get => _filterStdName; set => SetProperty(ref _filterStdName, value); } + + private string? _filterRubberMaterialName; + public string? FilterRubberMaterialName { get => _filterRubberMaterialName; set => SetProperty(ref _filterRubberMaterialName, value); } + + private string? _filterEnableStatus; + public string? FilterEnableStatus { get => _filterEnableStatus; set => SetProperty(ref _filterEnableStatus, value); } + + public ObservableCollection> EnableStatusOptions { get; } = new(); + + public DelegateCommand SearchCommand { get; } + public DelegateCommand ResetCommand { get; } + public DelegateCommand ViewDetailCommand { get; } + public DelegateCommand PrevPageCommand { get; } + public DelegateCommand NextPageCommand { get; } + + public RubberQuickTestStdListViewModel( + IRubberQuickTestStdService stdService, + IJeecgDictSyncService dictSyncService, + IContainerExtension container, + IRegionManager regionManager) : base(container, regionManager) + { + _stdService = stdService; + _dictSyncService = dictSyncService; + + SearchCommand = new DelegateCommand(async () => { PageNo = 1; await LoadAsync(); }); + ResetCommand = new DelegateCommand(async () => + { + FilterStdName = null; + FilterRubberMaterialName = null; + FilterEnableStatus = null; + PageNo = 1; + await LoadAsync(); + }); + ViewDetailCommand = new DelegateCommand(async x => await ShowDetailAsync(x)); + PrevPageCommand = new DelegateCommand(async () => { if (PageNo > 1) { PageNo--; await LoadAsync(); } }); + NextPageCommand = new DelegateCommand(async () => { if ((long)PageNo * PageSize < Total) { PageNo++; await LoadAsync(); } }); + + _changedToken = _eventAggregator.GetEvent() + .Subscribe(async _ => await LoadAsync(), ThreadOption.UIThread); + + _ = InitializeAsync(); + } + + private async Task InitializeAsync() + { + try + { + await LoadDictOptionsAsync(); + await UIHelper.WaitForRenderAsync(); + await LoadAsync(); + } + catch (Exception ex) + { + Debug.WriteLine($"快检实验标准列表初始化失败: {ex.Message}"); + } + } + + private async Task LoadDictOptionsAsync() + { + try + { + var opts = await _dictSyncService.GetDictOptionsAsync("xslmes_rubber_quick_test_std_enable_status", includeAll: true); + EnableStatusOptions.Clear(); + foreach (var item in opts) EnableStatusOptions.Add(item); + } + catch + { + EnableStatusOptions.Clear(); + EnableStatusOptions.Add(new KeyValuePair("全部", "")); + EnableStatusOptions.Add(new KeyValuePair("使用中", "1")); + EnableStatusOptions.Add(new KeyValuePair("已停用", "0")); + } + } + + public async Task LoadAsync() + { + try + { + IsLoading = true; + var result = await _stdService.PageAsync( + PageNo, PageSize, FilterStdName, FilterRubberMaterialName, FilterEnableStatus); + Items = new ObservableCollection(result.Records); + Total = result.Total; + } + catch (Exception ex) + { + Growl.Error($"加载快检实验标准失败:{ex.Message}"); + } + finally + { + IsLoading = false; + } + } + + private async Task ShowDetailAsync(MesXslRubberQuickTestStd? row) + { + if (row?.Id == null) return; + try + { + var detail = await _stdService.GetByIdAsync(row.Id); + if (detail == null) + { + Growl.Warning("未找到该实验标准,可能已被删除"); + await LoadAsync(); + return; + } + + await HandyControl.Controls.Dialog.Show() + .Initialize(vm => vm.Initialize(detail)) + .GetResultAsync(); + } + catch (Exception ex) + { + Growl.Error($"打开详情失败:{ex.Message}"); + } + } + + protected override void CleanUp() + { + base.CleanUp(); + if (_changedToken != null) + { + _eventAggregator.GetEvent().Unsubscribe(_changedToken); + _changedToken = null; + } + } +} diff --git a/yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml b/yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml new file mode 100644 index 00000000..e16c3a26 --- /dev/null +++ b/yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml @@ -0,0 +1,301 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +