From dea9b7a58c43c4fdbfb0cae4a7a7685d46cecc97 Mon Sep 17 00:00:00 2001 From: jiangxh <1217934998@qq.com> Date: Thu, 30 Jul 2026 17:40:31 +0800 Subject: [PATCH] =?UTF-8?q?=E9=85=8D=E5=90=88=E7=A4=BA=E6=96=B9=E7=94=9F?= =?UTF-8?q?=E6=88=90=E6=B7=B7=E7=82=BC=E7=A4=BA=E6=96=B9=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jeecg-module-xslmes/doc/代码修改日志 | 29 +++ .../executor/RegistryStageRevertExecutor.java | 22 ++ .../executor/RegistryStageSyncExecutor.java | 12 + .../service/IMesXslMixerPsCompileService.java | 16 ++ .../service/IMesXslMixingSpecService.java | 5 +- .../impl/MesXslFormulaSpecServiceImpl.java | 218 ++++++++++++++---- .../impl/MesXslMixerPsCompileServiceImpl.java | 40 ++++ .../impl/MesXslMixingSpecServiceImpl.java | 82 +++++-- .../org/jeecg/JeecgSystemApplication.java | 2 +- .../mesXslMixingSpec/MesXslMixingSpec.data.ts | 42 +++- .../RawMaterialEntryEditDialogViewModel.cs | 5 +- .../WeightRecordPickerDialogViewModel.cs | 62 ++++- .../WeightRecordEditDialogViewModel.cs | 72 +++++- .../WeightRecordPickerDialogView.xaml | 28 ++- .../WeightRecordEditDialogView.xaml | 13 +- 15 files changed, 541 insertions(+), 107 deletions(-) diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 index 4a01c44c..e85818cc 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 @@ -1361,3 +1361,32 @@ jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts -- author:jiangxh---date:20260730--for: ϡб/أʱԶ뽺һ --- jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/controller/MesMaterialController.java jeecgboot-vue3/src/views/mes/material/MesMaterial.data.ts + +-- author:jiangxh---date:20260730--for: ʾɡƴ汾ţϸϲƴ汾̶Ϊ --- +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java + +-- author:jiangxh---date:20260730--for: ʾɡͬһʾһΣɾ --- +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java + +-- author:jiangxh---date:20260730--for: ʾɾͣͬɾϢ --- +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java + +-- author:jiangxh---date:20260730--for: ʾɡĸ;NP FORһι;ȡ --- +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java + +-- author:jiangxh---date:20260730--for: ʾ𽺼ϼϸۼбλС --- +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts + +-- author:jiangxh---date:20260730--for: ʾ𽺼ϼϸбλС --- +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts + +-- author:jiangxh---date:20260730--for: PSɷ׼/ʾʽ(recognition_pass) --- +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerPsCompileService.java +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerPsCompileServiceImpl.java +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixingSpecService.java +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/executor/RegistryStageSyncExecutor.java +jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/executor/RegistryStageRevertExecutor.java diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/executor/RegistryStageRevertExecutor.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/executor/RegistryStageRevertExecutor.java index df113bc0..ba75b466 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/executor/RegistryStageRevertExecutor.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/executor/RegistryStageRevertExecutor.java @@ -9,6 +9,7 @@ import org.jeecg.modules.xslmes.approval.integration.entity.MesXslBizDocRegistry import org.jeecg.modules.xslmes.approval.integration.entity.MesXslIntegrationAction; import org.jeecg.modules.xslmes.approval.integration.service.IApprovalTraceSyncService; import org.jeecg.modules.xslmes.approval.integration.service.IMesXslBizDocRegistryService; +import org.jeecg.modules.xslmes.service.IMesXslMixerPsCompileService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; @@ -26,6 +27,12 @@ public class RegistryStageRevertExecutor implements IIntegrationActionExecutor { private IApprovalTraceSyncService approvalTraceSyncService; @Autowired private JdbcTemplate jdbcTemplate; + //update-begin---author:jiangxh ---date:20260730 for:【密炼PS】集成方案批准后联动示方正式发布----------- + @Autowired + private IMesXslMixerPsCompileService mesXslMixerPsCompileService; + + private static final String BIZ_TABLE_MIXER_PS = "mes_xsl_mixer_ps_compile"; + //update-end---author:jiangxh ---date:20260730 for:【密炼PS】集成方案批准后联动示方正式发布----------- @Override public String supportActionType() { return "REGISTRY_STAGE_REVERT"; @@ -57,6 +64,16 @@ public class RegistryStageRevertExecutor implements IIntegrationActionExecutor { RegistryStageFieldHelper.assertIdentifier(statusField); RegistryStageFieldHelper.assertIdentifier(bizTable); + //update-begin---author:jiangxh ---date:20260730 for:【密炼PS】集成方案批准后联动示方正式发布----------- + String previousStatus = null; + if (BIZ_TABLE_MIXER_PS.equals(bizTable)) { + Object current = jdbcTemplate.queryForObject( + "SELECT `" + statusField + "` FROM `" + bizTable + "` WHERE id = ?", + Object.class, bizId); + previousStatus = current == null ? null : String.valueOf(current).trim(); + } + //update-end---author:jiangxh ---date:20260730 for:【密炼PS】集成方案批准后联动示方正式发布----------- + //update-begin---author:GHT ---date:20260609 for:【审批注册中心】回退只重置业务表状态,操作人/时间由痕迹表承载----------- int affected = jdbcTemplate.update( "UPDATE `" + bizTable + "` SET `" + statusField + "`=? WHERE id=?", @@ -67,6 +84,11 @@ public class RegistryStageRevertExecutor implements IIntegrationActionExecutor { } approvalTraceSyncService.revertToStage(bizTable, bizId, targetStage); + //update-begin---author:jiangxh ---date:20260730 for:【密炼PS】集成方案批准后联动示方正式发布----------- + if (BIZ_TABLE_MIXER_PS.equals(bizTable)) { + mesXslMixerPsCompileService.cascadeRelatedAfterStageRevert(bizId, previousStatus, targetStage); + } + //update-end---author:jiangxh ---date:20260730 for:【密炼PS】集成方案批准后联动示方正式发布----------- log.info("[集成引擎][REGISTRY_STAGE_REVERT] table={} id={} targetStage={}", bizTable, bizId, targetStage); return "环节回退成功: " + targetStage; } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/executor/RegistryStageSyncExecutor.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/executor/RegistryStageSyncExecutor.java index 9dbf1847..cc74fd87 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/executor/RegistryStageSyncExecutor.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/executor/RegistryStageSyncExecutor.java @@ -13,6 +13,7 @@ import org.jeecg.modules.xslmes.approval.integration.entity.MesXslIntegrationAct import org.jeecg.modules.xslmes.approval.integration.entity.MesXslIntegrationPlan; import org.jeecg.modules.xslmes.approval.integration.service.IApprovalTraceSyncService; import org.jeecg.modules.xslmes.approval.integration.service.IMesXslBizDocRegistryService; +import org.jeecg.modules.xslmes.service.IMesXslMixerPsCompileService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; @@ -30,6 +31,12 @@ public class RegistryStageSyncExecutor implements IIntegrationActionExecutor { private IApprovalTraceSyncService approvalTraceSyncService; @Autowired private JdbcTemplate jdbcTemplate; + //update-begin---author:jiangxh ---date:20260730 for:【密炼PS】集成方案批准后联动示方正式发布----------- + @Autowired + private IMesXslMixerPsCompileService mesXslMixerPsCompileService; + //update-end---author:jiangxh ---date:20260730 for:【密炼PS】集成方案批准后联动示方正式发布----------- + + private static final String BIZ_TABLE_MIXER_PS = "mes_xsl_mixer_ps_compile"; @Override public String supportActionType() { @@ -96,6 +103,11 @@ public class RegistryStageSyncExecutor implements IIntegrationActionExecutor { } approvalTraceSyncService.syncStage(bizTable, bizId, stage, operator, now); + //update-begin---author:jiangxh ---date:20260730 for:【密炼PS】集成方案批准后联动示方正式发布----------- + if (BIZ_TABLE_MIXER_PS.equals(bizTable)) { + mesXslMixerPsCompileService.cascadeRelatedAfterStageSync(bizId, statusAfter, operator, now); + } + //update-end---author:jiangxh ---date:20260730 for:【密炼PS】集成方案批准后联动示方正式发布----------- log.info("[集成引擎][REGISTRY_STAGE_SYNC] table={} id={} stage={} statusAfter={} operator={}", bizTable, bizId, stage, statusAfter, operator); return "环节同步成功: " + ApprovalStageResolver.stageLabel(stage) + " → 状态=" + statusAfter; diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerPsCompileService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerPsCompileService.java index b603460f..082628cf 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerPsCompileService.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerPsCompileService.java @@ -34,4 +34,20 @@ public interface IMesXslMixerPsCompileService extends IService { //update-begin---author:cursor ---date:20260526 for:【XSLMES-20260526-A61】混炼示方密炼PS审批联动同步审批人----------- /** - * 密炼PS校对/审核/批准后,按发行编号(PS编码)同步关联混炼示方审批人 + * 密炼PS校对/审核/批准后,按发行编号(PS编码)同步关联混炼示方状态与审批人。 + * 批准时状态为 recognition_pass(承认审批通过-即正式发布)。 * * @param ps 已更新后的密炼PS编制单 * @param mixerPsTargetStatus 密炼PS目标状态:proofread / audit / approve @@ -50,7 +51,7 @@ public interface IMesXslMixingSpecService extends IService { //update-begin---author:GHT ---date:2026-05-29 for:【QH-MES审批流设计】密炼PS拒绝/撤回联动回退混炼示方----------- /** - * 密炼PS拒绝/撤回时,按发行编号(PS编码)清空关联混炼示方高于目标状态的审批人痕迹。 + * 密炼PS拒绝/撤回时,按发行编号(PS编码)将关联混炼示方回退到目标状态,并清空高于目标状态的审批人痕迹。 * * @param ps 已回退后的密炼PS编制单 * @param mixerPsTargetStatus 密炼PS回退后的目标状态:compile / proofread / audit diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java index db85aa08..6c83eceb 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java @@ -565,6 +565,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl items = new ArrayList<>(); int aIndex = 0; @@ -575,20 +578,23 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl categoryIdCache = new HashMap<>(); assertRequiredRubberMaterialsExist(request.getRows(), formula, lines); @@ -659,7 +668,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl allRows, + MesXslFormulaSpec formula, + Map categoryNameCache) { + if (row == null) { + return ""; + } + boolean isFinalStage = "Q".equalsIgnoreCase(resolveMixingMaterialStep(row)); + if (isFinalStage) { + return resolveFinalMixingPurpose(formula, categoryNameCache); + } + String nextSpecCode = findNextStageSpecCode(row, allRows); + if (StringUtils.isNotBlank(nextSpecCode)) { + return "NP FOR " + nextSpecCode.trim(); + } + // 无下一段时回退为终炼用途规则 + return resolveFinalMixingPurpose(formula, categoryNameCache); + } + + /** 终炼用途:取所选胶料的类别名(如注射胶);类别为空时回退配合示方用途 */ + private String resolveFinalMixingPurpose(MesXslFormulaSpec formula, Map categoryNameCache) { + String categoryId = resolveGeneratedRubberCategoryId(formula); + String categoryName = resolveCategoryName(categoryId, categoryNameCache); + if (StringUtils.isNotBlank(categoryName)) { + return categoryName.trim(); + } + if (formula != null && StringUtils.isNotBlank(formula.getPurpose())) { + return formula.getPurpose().trim(); + } + return ""; + } + + /** 按混合段序号找下一段规格编号 */ + private String findNextStageSpecCode( + MesXslFormulaMixingGenerateRowVO current, + List allRows) { + if (current == null || current.getStageIndex() == null || CollectionUtils.isEmpty(allRows)) { + return null; + } + int currentStage = current.getStageIndex(); + MesXslFormulaMixingGenerateRowVO next = null; + for (MesXslFormulaMixingGenerateRowVO row : allRows) { + if (row == null || row.getStageIndex() == null || StringUtils.isBlank(row.getSpecCode())) { + continue; + } + int stage = row.getStageIndex(); + if (stage <= currentStage) { + continue; + } + if (next == null || stage < next.getStageIndex()) { + next = row; + } + } + return next != null ? next.getSpecCode().trim() : null; + } + //update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】母炼/终炼用途拼接规则----------- + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】生成混炼示方时按设备有效体积计算填充体积----------- /** 配合示方整体比重(终炼胶比重)= TOTAL PHR ÷ 全部明细体积合计 */ private BigDecimal resolveCompoundSpecificGravity(MesXslFormulaSpec formula, List lines) { @@ -804,6 +879,53 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl items) { + if (CollectionUtils.isEmpty(items)) { + return; + } + LinkedHashSet specNames = new LinkedHashSet<>(); + for (MesXslFormulaMixingGeneratePreviewItemVO item : items) { + if (item != null && StringUtils.isNotBlank(item.getSpecCode())) { + specNames.add(item.getSpecCode().trim()); + } + } + assertMixingSpecNamesNotExist(specNames); + } + + /** 确认行:若对应规格混炼示方已存在则禁止再次生成 */ + private void assertMixingSpecsNotYetGeneratedByRows(List rows) { + if (CollectionUtils.isEmpty(rows)) { + return; + } + LinkedHashSet specNames = new LinkedHashSet<>(); + for (MesXslFormulaMixingGenerateRowVO row : rows) { + if (row != null && StringUtils.isNotBlank(row.getSpecCode())) { + specNames.add(row.getSpecCode().trim()); + } + } + assertMixingSpecNamesNotExist(specNames); + } + + /** 若已存在同规格混炼示方,则禁止再次生成 */ + private void assertMixingSpecNamesNotExist(Collection specNames) { + if (CollectionUtils.isEmpty(specNames)) { + return; + } + long count = mesXslMixingSpecService.count( + new LambdaQueryWrapper() + .in(MesXslMixingSpec::getSpecName, specNames) + .and(w -> w.eq(MesXslMixingSpec::getDelFlag, CommonConstant.DEL_FLAG_0) + .or() + .isNull(MesXslMixingSpec::getDelFlag))); + if (count > 0) { + throw new IllegalArgumentException("该配合示方已生成过混炼示方,请先删除对应混炼示方后再重新生成"); + } + } + //update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】同一配合示方仅允许生成一次----------- + //update-begin---author:jiangxh ---date:20260729 for:【混炼示方生成】B/F胶料改为胶料列表匹配,不存在则提示先维护----------- //update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】预览项转生成行供胶料匹配校验----------- /** 预览行转为生成行结构,供胶料匹配校验复用 */ @@ -829,7 +951,7 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl requiredCodes = new LinkedHashSet<>(); String rubberName = resolveRubberName(formula); for (MesXslFormulaMixingGenerateRowVO row : rows) { - if (row == null || StringUtils.isBlank(row.getSpecCode())) { + if (row == null) { continue; } - requiredCodes.add(row.getSpecCode().trim()); String stepFilter = resolveMixingMaterialStep(row); int mixingColumn = resolveMixingColumn(row, formula); + //update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】胶料匹配用不含版本号的B/F名----------- if ("Q".equalsIgnoreCase(stepFilter)) { + if (StringUtils.isNotBlank(rubberName)) { + requiredCodes.add(buildBfRubberSpecCode("F", rubberName)); + } int lastBSegment = resolveLastBSegmentIndex(formula, lines); if (lastBSegment > 0 && StringUtils.isNotBlank(rubberName)) { - //update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶匹配不拼版本后缀----------- requiredCodes.add(buildBfRubberSpecCode("B" + lastBSegment, rubberName)); - //update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶匹配不拼版本后缀----------- } - } else if (mixingColumn > 1 && StringUtils.isNotBlank(rubberName)) { - //update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶匹配不拼版本后缀----------- - requiredCodes.add(buildBfRubberSpecCode("B" + (mixingColumn - 1), rubberName)); - //update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶匹配不拼版本后缀----------- + } else if (StringUtils.isNotBlank(rubberName)) { + requiredCodes.add(buildBfRubberSpecCode("B" + mixingColumn, rubberName)); + if (mixingColumn > 1) { + requiredCodes.add(buildBfRubberSpecCode("B" + (mixingColumn - 1), rubberName)); + } } + //update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】胶料匹配用不含版本号的B/F名----------- } List missing = new ArrayList<>(); for (String code : requiredCodes) { @@ -1022,9 +1147,8 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl lines) { if (CollectionUtils.isEmpty(lines)) { @@ -1263,7 +1384,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl specNames = new LinkedHashSet<>(); - for (MesXslMixingSpec main : mains) { - if (main != null && StringUtils.isNotBlank(main.getSpecName())) { - specNames.add(main.getSpecName().trim()); - } - } - for (String specName : specNames) { - syncDeleteGeneratedRubberMixerMaterial(specName); - } + //update-begin---author:jiangxh ---date:20260730 for:【混炼示方删除】停用同步删除胶料信息----------- + // 胶料改为手工维护并从列表匹配,删除混炼示方时不再同步删除胶料信息 + // Set specNames = new LinkedHashSet<>(); + // for (MesXslMixingSpec main : mains) { + // if (main != null && StringUtils.isNotBlank(main.getSpecName())) { + // specNames.add(main.getSpecName().trim()); + // } + // } + // for (String specName : specNames) { + // syncDeleteGeneratedRubberMixerMaterial(specName); + // } + //update-end---author:jiangxh ---date:20260730 for:【混炼示方删除】停用同步删除胶料信息----------- //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A56】混炼示方批量删除性能优化----------- } @@ -421,6 +424,13 @@ public class MesXslMixingSpecServiceImpl extends ServiceImpl 0 && index === unitWeightIndex - 1; return { diff --git a/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/RawMaterialEntryEditDialogViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/RawMaterialEntryEditDialogViewModel.cs index d278e758..77007198 100644 --- a/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/RawMaterialEntryEditDialogViewModel.cs +++ b/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/RawMaterialEntryEditDialogViewModel.cs @@ -526,7 +526,10 @@ public class RawMaterialEntryEditDialogViewModel : BaseViewModel, IDialogResulta .Initialize(vm => { pickerVm = vm; - vm.Initialize(Entry?.BillNo); + vm.Initialize( + Entry?.BillNo, + SelectedMaterial?.Id ?? Entry?.MaterialId, + SelectedMaterial?.MaterialName ?? Entry?.MaterialName); }) .GetResultAsync()); } diff --git a/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/WeightRecordPickerDialogViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/WeightRecordPickerDialogViewModel.cs index 2bf4a33e..149430a6 100644 --- a/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/WeightRecordPickerDialogViewModel.cs +++ b/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/WeightRecordPickerDialogViewModel.cs @@ -24,6 +24,26 @@ public class WeightRecordPickerDialogViewModel : BaseViewModel, IDialogResultabl set => SetProperty(ref _searchPlateNumber, value); } + /// 入场记录已选密炼物料ID:有值时仅展示关联该物料的磅单。 + private string? _filterMixerMaterialId; + private string? _filterMixerMaterialName; + + public string FilterHint + { + get + { + if (string.IsNullOrWhiteSpace(_filterMixerMaterialId)) + { + return "未选择密炼物料时显示全部进厂磅单;已选物料时仅匹配含该物料的磅单。"; + } + + var name = string.IsNullOrWhiteSpace(_filterMixerMaterialName) + ? _filterMixerMaterialId + : _filterMixerMaterialName; + return $"已按密炼物料「{name}」自动匹配关联磅单"; + } + } + public ObservableCollection Records { get; } = new(); private MesXslWeightRecord? _selectedRecord; @@ -40,7 +60,7 @@ public class WeightRecordPickerDialogViewModel : BaseViewModel, IDialogResultabl } public string SelectedRecordDisplay => _selectedRecord != null - ? $"[{_selectedRecord.BillNo}] 供应商:{_selectedRecord.SenderUnit ?? "-"}" + ? $"[{_selectedRecord.BillNo}] 供应商:{_selectedRecord.SenderUnit ?? "-"} 物料:{_selectedRecord.MixerMaterialNames ?? "-"}" : "选中榜单后点击「确认选择」"; public bool HasSelectedRecord => _selectedRecord != null; @@ -67,16 +87,24 @@ public class WeightRecordPickerDialogViewModel : BaseViewModel, IDialogResultabl SearchCommand = new DelegateCommand(async () => await LoadAsync()); ConfirmCommand = new DelegateCommand(Confirm, () => SelectedRecord != null); CancelCommand = new DelegateCommand(() => CloseAction?.Invoke()); - _ = LoadAsync(); + // 不在构造时加载:等 Initialize 带入密炼物料过滤条件后再查,避免竞态覆盖筛选结果 } - public void Initialize(string? billNo) + /// 已选榜单号(用于回显搜索) + /// 已选密炼物料ID,有值则只匹配含该物料的磅单 + /// 密炼物料名称(提示展示) + public void Initialize(string? billNo, string? mixerMaterialId = null, string? mixerMaterialName = null) { + _filterMixerMaterialId = string.IsNullOrWhiteSpace(mixerMaterialId) ? null : mixerMaterialId.Trim(); + _filterMixerMaterialName = string.IsNullOrWhiteSpace(mixerMaterialName) ? null : mixerMaterialName.Trim(); + RaisePropertyChanged(nameof(FilterHint)); + if (!string.IsNullOrWhiteSpace(billNo)) { SearchBillNo = billNo.Trim(); - _ = LoadAsync(); } + + _ = LoadAsync(); } private async Task LoadAsync() @@ -92,7 +120,7 @@ public class WeightRecordPickerDialogViewModel : BaseViewModel, IDialogResultabl filterInoutDirection: "1"); Records.Clear(); - foreach (var record in result.Records) + foreach (var record in result.Records.Where(MatchesSelectedMixerMaterial)) { Records.Add(record); } @@ -102,6 +130,11 @@ public class WeightRecordPickerDialogViewModel : BaseViewModel, IDialogResultabl SelectedRecord = Records.FirstOrDefault(x => string.Equals(x.BillNo, SearchBillNo, StringComparison.OrdinalIgnoreCase)); } + else if (!string.IsNullOrWhiteSpace(_filterMixerMaterialId) && Records.Count == 1) + { + // 仅匹配到一条时自动选中,便于快速确认 + SelectedRecord = Records[0]; + } } catch { @@ -113,6 +146,25 @@ public class WeightRecordPickerDialogViewModel : BaseViewModel, IDialogResultabl } } + /// 未指定物料时不过滤;指定时要求磅单 MixerMaterialIds 含该ID。 + private bool MatchesSelectedMixerMaterial(MesXslWeightRecord record) + { + if (string.IsNullOrWhiteSpace(_filterMixerMaterialId)) + { + return true; + } + + if (string.IsNullOrWhiteSpace(record.MixerMaterialIds)) + { + return false; + } + + var parts = record.MixerMaterialIds.Split( + new[] { ';', ',', ';', ',' }, + StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + return parts.Any(p => string.Equals(p, _filterMixerMaterialId, StringComparison.OrdinalIgnoreCase)); + } + private void Confirm() { if (SelectedRecord == null) diff --git a/yy-admin-master/YY.Admin/ViewModels/WeightRecord/WeightRecordEditDialogViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/WeightRecord/WeightRecordEditDialogViewModel.cs index f0fdd15d..29eb18ec 100644 --- a/yy-admin-master/YY.Admin/ViewModels/WeightRecord/WeightRecordEditDialogViewModel.cs +++ b/yy-admin-master/YY.Admin/ViewModels/WeightRecord/WeightRecordEditDialogViewModel.cs @@ -34,6 +34,44 @@ public class WeightRecordEditDialogViewModel : BaseViewModel, IDialogResultable< public bool IsAddMode => string.IsNullOrWhiteSpace(Record?.Id); public string DialogTitle => IsAddMode ? "新增磅单" : "编辑磅单"; + /// 毛重输入:变更后自动重算净重 + public double? GrossWeightInput + { + get => Record?.GrossWeight; + set + { + if (Record == null || Nullable.Equals(Record.GrossWeight, value)) return; + Record.GrossWeight = value; + RaisePropertyChanged(nameof(GrossWeightInput)); + RecalcNetWeight(); + } + } + + /// 皮重输入:变更后自动用毛重-皮重填充净重 + public double? TareWeightInput + { + get => Record?.TareWeight; + set + { + if (Record == null || Nullable.Equals(Record.TareWeight, value)) return; + Record.TareWeight = value; + RaisePropertyChanged(nameof(TareWeightInput)); + RecalcNetWeight(); + } + } + + /// 净重(只读展示,由毛重/皮重自动计算) + public double? NetWeightInput + { + get => Record?.NetWeight; + private set + { + if (Record == null || Nullable.Equals(Record.NetWeight, value)) return; + Record.NetWeight = value; + RaisePropertyChanged(nameof(NetWeightInput)); + } + } + public ObservableCollection> InoutDirectionOptions { get; } = new(); private bool _result; @@ -121,6 +159,7 @@ public class WeightRecordEditDialogViewModel : BaseViewModel, IDialogResultable< }; RaisePropertyChanged(nameof(IsAddMode)); RaisePropertyChanged(nameof(DialogTitle)); + RaiseWeightInputsChanged(); } public void InitializeForEdit(MesXslWeightRecord record) @@ -151,6 +190,31 @@ public class WeightRecordEditDialogViewModel : BaseViewModel, IDialogResultable< RaisePropertyChanged(nameof(HasSelectedMixerMaterials)); RaisePropertyChanged(nameof(IsAddMode)); RaisePropertyChanged(nameof(DialogTitle)); + RaiseWeightInputsChanged(); + // 编辑打开时若已有毛重+皮重,立即校正净重展示 + RecalcNetWeight(); + } + + private void RaiseWeightInputsChanged() + { + RaisePropertyChanged(nameof(GrossWeightInput)); + RaisePropertyChanged(nameof(TareWeightInput)); + RaisePropertyChanged(nameof(NetWeightInput)); + } + + /// 毛重、皮重均有效时:净重 = 毛重 - 皮重(保留两位小数) + private void RecalcNetWeight() + { + if (Record == null) return; + if (Record.GrossWeight.HasValue && Record.GrossWeight.Value > 0 + && Record.TareWeight.HasValue && Record.TareWeight.Value > 0) + { + NetWeightInput = Math.Round(Record.GrossWeight.Value - Record.TareWeight.Value, 2); + } + else + { + NetWeightInput = null; + } } private async Task SaveAsync() @@ -168,12 +232,8 @@ public class WeightRecordEditDialogViewModel : BaseViewModel, IDialogResultable< return; } - // 净重自动计算(0 视为未称,不计算净重) - if (Record.GrossWeight.HasValue && Record.GrossWeight.Value > 0 - && Record.TareWeight.HasValue && Record.TareWeight.Value > 0) - Record.NetWeight = Math.Round(Record.GrossWeight.Value - Record.TareWeight.Value, 2); - else - Record.NetWeight = null; + // 保存前再算一次,防止未触发属性变更时净重未更新 + RecalcNetWeight(); // 写入密炼物料 Record.MixerMaterialIds = _mixerMaterialIds; diff --git a/yy-admin-master/YY.Admin/Views/RawMaterialEntry/WeightRecordPickerDialogView.xaml b/yy-admin-master/YY.Admin/Views/RawMaterialEntry/WeightRecordPickerDialogView.xaml index cd3e1ef1..98ef8c5e 100644 --- a/yy-admin-master/YY.Admin/Views/RawMaterialEntry/WeightRecordPickerDialogView.xaml +++ b/yy-admin-master/YY.Admin/Views/RawMaterialEntry/WeightRecordPickerDialogView.xaml @@ -8,10 +8,11 @@ xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True" mc:Ignorable="d" - Width="760"> + Width="920"> + @@ -34,7 +35,11 @@ Padding="0" HorizontalAlignment="Right" VerticalAlignment="Center"/> - + + + @@ -70,7 +75,7 @@ - - + + + - - - - + + + + - - diff --git a/yy-admin-master/YY.Admin/Views/WeightRecord/WeightRecordEditDialogView.xaml b/yy-admin-master/YY.Admin/Views/WeightRecord/WeightRecordEditDialogView.xaml index 79ee9866..d0f1b5dc 100644 --- a/yy-admin-master/YY.Admin/Views/WeightRecord/WeightRecordEditDialogView.xaml +++ b/yy-admin-master/YY.Admin/Views/WeightRecord/WeightRecordEditDialogView.xaml @@ -144,7 +144,7 @@ - - - + -