From 680eb6c54c621e7fb3de5d922145efa5cd62826f Mon Sep 17 00:00:00 2001 From: geht <2947093423@qq.com> Date: Fri, 22 May 2026 12:15:05 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=85=8D=E5=90=88?= =?UTF-8?q?=E7=A4=BA=E6=96=B9=E6=A8=A1=E5=9D=97=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AF=86=E7=82=BCPS=E5=AE=A1=E6=89=B9=E8=81=94=E5=8A=A8?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=94=AF=E6=8C=81=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E4=B8=8E=E5=AE=A1=E6=89=B9=E4=BA=BA=E5=90=8C=E6=AD=A5=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=9B=B8=E5=85=B3=E6=9C=8D=E5=8A=A1=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=EF=BC=8C=E8=B0=83=E6=95=B4=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=AD=97=E5=85=B8=EF=BC=8C=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E6=95=B0=E6=8D=AE=E4=B8=80=E8=87=B4=E6=80=A7?= =?UTF-8?q?=E5=92=8C=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jeecg-module-xslmes/doc/代码修改日志 | 8 ++++ .../service/IMesXslFormulaSpecService.java | 11 +++++ .../impl/MesXslFormulaSpecServiceImpl.java | 34 ++++++++++++++ .../impl/MesXslMixerPsCompileServiceImpl.java | 8 ++++ ...2_97__mes_xsl_formula_spec_status_dict.sql | 45 +++++++++++++++++++ qhmes.code-workspace | 12 ++++- 6 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_97__mes_xsl_formula_spec_status_dict.sql diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 index 419402b..3dc3f26 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 @@ -103,3 +103,11 @@ jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecMo -- author:cursor---date:20260521--for: 【配合示方】编辑打开时基本资料闪清修复 --- jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue + +-- author:cursor---date:20260522--for: 【配合示方】状态字典调整为审批流程8项 --- +jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_97__mes_xsl_formula_spec_status_dict.sql + +-- author:cursor---date:20260522--for: 【配合示方】密炼PS校对/审核/批准联动同步状态与审批人 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerPsCompileServiceImpl.java diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java index 65f453b..8bab67c 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java @@ -6,6 +6,7 @@ import java.util.Collection; import java.util.List; import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec; import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine; +import org.jeecg.modules.xslmes.entity.MesXslMixerPsCompile; public interface IMesXslFormulaSpecService extends IService { @@ -25,4 +26,14 @@ public interface IMesXslFormulaSpecService extends IService { * 生成胶料代号:D + 胶料名称 + 分类键值(S/P/T/C) + 版本号(A01-Z01) */ String generateRubberCode(String rubberMaterialId, String category, String excludeSpecId); + + //update-begin---author:cursor ---date:20260522 for:【配合示方】密炼PS审批联动同步状态与审批人----------- + /** + * 密炼PS校对/审核/批准后,按发行编号(PS编码)同步关联配合示方状态与审批人 + * + * @param ps 已更新后的密炼PS编制单 + * @param mixerPsTargetStatus 密炼PS目标状态:proofread / audit / approve + */ + void syncFromMixerPsWorkflow(MesXslMixerPsCompile ps, String mixerPsTargetStatus); + //update-end---author:cursor ---date:20260522 for:【配合示方】密炼PS审批联动同步状态与审批人----------- } 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 cdb7d34..dcdeaf2 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 @@ -21,8 +21,10 @@ import org.jeecg.modules.mes.material.entity.MesMaterial; import org.jeecg.modules.mes.material.entity.MesMixerMaterial; import org.jeecg.modules.mes.material.service.IMesMaterialService; import org.jeecg.modules.mes.material.service.IMesMixerMaterialService; +import org.jeecg.common.util.oConvertUtils; import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec; import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine; +import org.jeecg.modules.xslmes.entity.MesXslMixerPsCompile; import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecLineMapper; import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecMapper; import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecService; @@ -400,4 +402,36 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl wrapper = new LambdaUpdateWrapper<>(); + wrapper.eq(MesXslFormulaSpec::getIssueNumber, ps.getPsCode()); + switch (mixerPsTargetStatus) { + case "proofread": + wrapper.set(MesXslFormulaSpec::getStatus, "submit") + .set(MesXslFormulaSpec::getProofreadBy, ps.getProofreadBy()) + .set(MesXslFormulaSpec::getProofreadTime, ps.getProofreadTime()); + break; + case "audit": + wrapper.set(MesXslFormulaSpec::getStatus, "review_pass") + .set(MesXslFormulaSpec::getAuditBy, ps.getAuditBy()) + .set(MesXslFormulaSpec::getAuditTime, ps.getAuditTime()); + break; + case "approve": + wrapper.set(MesXslFormulaSpec::getStatus, "recognition_pass") + .set(MesXslFormulaSpec::getApproveBy, ps.getApproveBy()) + .set(MesXslFormulaSpec::getApproveTime, ps.getApproveTime()); + break; + default: + return; + } + wrapper.set(MesXslFormulaSpec::getUpdateTime, new Date()); + this.update(wrapper); + } + //update-end---author:cursor ---date:20260522 for:【配合示方】密炼PS审批联动同步状态与审批人----------- } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerPsCompileServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerPsCompileServiceImpl.java index 70c5137..3779502 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerPsCompileServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerPsCompileServiceImpl.java @@ -7,7 +7,9 @@ import java.util.List; import org.jeecg.common.util.oConvertUtils; import org.jeecg.modules.xslmes.entity.MesXslMixerPsCompile; import org.jeecg.modules.xslmes.mapper.MesXslMixerPsCompileMapper; +import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecService; import org.jeecg.modules.xslmes.service.IMesXslMixerPsCompileService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -18,6 +20,9 @@ import org.springframework.transaction.annotation.Transactional; public class MesXslMixerPsCompileServiceImpl extends ServiceImpl implements IMesXslMixerPsCompileService { + @Autowired + private IMesXslFormulaSpecService mesXslFormulaSpecService; + //update-begin---author:jiangxh ---date:20260520 for:【密炼PS编制】批量流转状态----------- @Override @Transactional(rollbackFor = Exception.class) @@ -44,6 +49,9 @@ public class MesXslMixerPsCompileServiceImpl extends ServiceImpl Date: Fri, 22 May 2026 16:34:33 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E6=96=B0=E5=A2=9EMES=E6=B7=B7=E7=82=BC?= =?UTF-8?q?=E7=A4=BA=E6=96=B9=E6=A8=A1=E5=9D=97=EF=BC=8C=E5=8C=85=E6=8B=AC?= =?UTF-8?q?=E4=B8=BB=E8=A1=A8=E5=8F=8A=E5=AD=90=E8=A1=A8=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E3=80=81=E6=8E=A7=E5=88=B6=E5=99=A8=E3=80=81=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=92=8C=E6=98=A0=E5=B0=84=E5=99=A8=E7=9A=84=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E5=A2=9E=E5=88=A0=E6=94=B9=E6=9F=A5?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E5=92=8C=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=BC=BA=E7=B3=BB=E7=BB=9F=E7=A8=B3=E5=AE=9A?= =?UTF-8?q?=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jeecg-module-xslmes/doc/代码修改日志 | 21 + .../MesXslMixingSpecController.java | 155 +++ .../xslmes/entity/MesXslMixingSpec.java | 165 +++ .../entity/MesXslMixingSpecDownStep.java | 71 + .../entity/MesXslMixingSpecMaterial.java | 65 + .../xslmes/entity/MesXslMixingSpecStep.java | 71 + .../xslmes/entity/MesXslMixingSpecTcu.java | 62 + .../MesXslMixingSpecDownStepMapper.java | 6 + .../xslmes/mapper/MesXslMixingSpecMapper.java | 6 + .../MesXslMixingSpecMaterialMapper.java | 6 + .../mapper/MesXslMixingSpecStepMapper.java | 6 + .../mapper/MesXslMixingSpecTcuMapper.java | 6 + .../service/IMesXslMixingSpecService.java | 39 + .../impl/MesXslMixingSpecServiceImpl.java | 339 +++++ .../xslmes/vo/MesXslMixingSpecPage.java | 22 + .../mysql/V3.9.2_98__mes_xsl_mixing_spec.sql | 195 +++ .../mesXslMixingSpec/MesXslMixingSpec.api.ts | 37 + .../mesXslMixingSpec/MesXslMixingSpec.data.ts | 587 +++++++++ .../mesXslMixingSpec/MesXslMixingSpecList.vue | 115 ++ .../MesXslMixingMaterialColumnSetting.vue | 166 +++ .../components/MesXslMixingSpecModal.vue | 1174 +++++++++++++++++ .../MesXslMixingTableRowHeightSetting.vue | 169 +++ 22 files changed, 3483 insertions(+) create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpec.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecDownStep.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecMaterial.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecStep.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecTcu.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecDownStepMapper.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMapper.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMaterialMapper.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecStepMapper.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecTcuMapper.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixingSpecService.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslMixingSpecPage.java create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_98__mes_xsl_mixing_spec.sql create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpecList.vue create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialColumnSetting.vue create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingTableRowHeightSetting.vue diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 index 3dc3f26..04a7f2a 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 @@ -111,3 +111,24 @@ jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9. jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerPsCompileServiceImpl.java + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A17】新增MES技术管理-混炼示方1主4子表及紧凑页 --- +jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_98__mes_xsl_mixing_spec.sql +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpec.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecMaterial.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecStep.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecDownStep.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecTcu.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslMixingSpecPage.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMapper.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMaterialMapper.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecStepMapper.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecDownStepMapper.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecTcuMapper.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixingSpecService.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpecList.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java new file mode 100644 index 0000000..52700e2 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java @@ -0,0 +1,155 @@ +package org.jeecg.modules.xslmes.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.aspect.annotation.AutoLog; +import org.jeecg.common.system.base.controller.JeecgController; +import org.jeecg.common.system.query.QueryGenerator; +import org.jeecg.common.util.oConvertUtils; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpec; +import org.jeecg.modules.xslmes.service.IMesXslMixingSpecService; +import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +/** + * MES 混炼示方 + */ +@Tag(name = "MES混炼示方") +@RestController +@RequestMapping("/xslmes/mesXslMixingSpec") +public class MesXslMixingSpecController extends JeecgController { + + @Autowired + private IMesXslMixingSpecService mesXslMixingSpecService; + + @Operation(summary = "MES混炼示方-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList( + MesXslMixingSpec model, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "keyword", required = false) String keyword, + HttpServletRequest req) { + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap()); + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方列表关键字查询----------- + if (oConvertUtils.isNotEmpty(keyword)) { + queryWrapper.and(w -> w.like("spec_name", keyword).or().like("issue_number", keyword).or().like("purpose", keyword).or().like("machine_name", keyword)); + } + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方列表关键字查询----------- + queryWrapper.orderByDesc("update_time").orderByDesc("create_time"); + Page page = new Page<>(pageNo, pageSize); + return Result.OK(mesXslMixingSpecService.page(page, queryWrapper)); + } + + @AutoLog(value = "MES混炼示方-添加") + @Operation(summary = "MES混炼示方-添加") + @RequiresPermissions("xslmes:mes_xsl_mixing_spec:add") + @PostMapping(value = "/add") + public Result add(@RequestBody MesXslMixingSpecPage page) { + String err = validateMain(page); + if (err != null) { + return Result.error(err); + } + MesXslMixingSpec main = new MesXslMixingSpec(); + BeanUtils.copyProperties(page, main); + mesXslMixingSpecService.saveMain(main, page.getMaterialList(), page.getStepList(), page.getDownStepList(), page.getTcuList()); + return Result.OK("添加成功!"); + } + + @AutoLog(value = "MES混炼示方-编辑") + @Operation(summary = "MES混炼示方-编辑") + @RequiresPermissions("xslmes:mes_xsl_mixing_spec:edit") + @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST}) + public Result edit(@RequestBody MesXslMixingSpecPage page) { + String err = validateMain(page); + if (err != null) { + return Result.error(err); + } + MesXslMixingSpec main = new MesXslMixingSpec(); + BeanUtils.copyProperties(page, main); + mesXslMixingSpecService.updateMain(main, page.getMaterialList(), page.getStepList(), page.getDownStepList(), page.getTcuList()); + return Result.OK("编辑成功!"); + } + + @AutoLog(value = "MES混炼示方-删除") + @Operation(summary = "MES混炼示方-通过id删除") + @RequiresPermissions("xslmes:mes_xsl_mixing_spec:delete") + @DeleteMapping(value = "/delete") + public Result delete(@RequestParam(name = "id", required = true) String id) { + mesXslMixingSpecService.delMain(id); + return Result.OK("删除成功!"); + } + + @AutoLog(value = "MES混炼示方-批量删除") + @Operation(summary = "MES混炼示方-批量删除") + @RequiresPermissions("xslmes:mes_xsl_mixing_spec:deleteBatch") + @DeleteMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) { + mesXslMixingSpecService.delBatchMain(Arrays.asList(ids.split(","))); + return Result.OK("批量删除成功!"); + } + + @Operation(summary = "MES混炼示方-通过id查询") + @GetMapping(value = "/queryById") + public Result queryById(@RequestParam(name = "id", required = true) String id) { + MesXslMixingSpecPage page = mesXslMixingSpecService.queryPageById(id); + if (page == null) { + return Result.error("未找到对应数据"); + } + return Result.OK(page); + } + + @Operation(summary = "MES混炼示方-发行编号候选") + @GetMapping(value = "/queryIssueNumberOptions") + public Result>> queryIssueNumberOptions( + @RequestParam(name = "keyword", required = false) String keyword) { + return Result.OK(mesXslMixingSpecService.queryIssueNumberOptions(keyword)); + } + + @Operation(summary = "MES混炼示方-用途候选") + @GetMapping(value = "/queryPurposeOptions") + public Result>> queryPurposeOptions( + @RequestParam(name = "keyword", required = false) String keyword) { + return Result.OK(mesXslMixingSpecService.queryPurposeOptions(keyword)); + } + + @RequiresPermissions("xslmes:mes_xsl_mixing_spec:exportXls") + @RequestMapping(value = "/exportXls") + public ModelAndView exportXls(HttpServletRequest request, MesXslMixingSpec model) { + return super.exportXls(request, model, MesXslMixingSpec.class, "混炼示方"); + } + + @RequiresPermissions("xslmes:mes_xsl_mixing_spec:importExcel") + @RequestMapping(value = "/importExcel", method = RequestMethod.POST) + public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + return super.importExcel(request, response, MesXslMixingSpec.class); + } + + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子保存校验----------- + private String validateMain(MesXslMixingSpecPage page) { + if (oConvertUtils.isEmpty(page.getSpecName())) { + return "请填写规格"; + } + if (oConvertUtils.isEmpty(page.getPurpose())) { + return "请选择用途"; + } + if (oConvertUtils.isEmpty(page.getIssueNumber())) { + return "请选择发行编号"; + } + return null; + } + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子保存校验----------- +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpec.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpec.java new file mode 100644 index 0000000..ea6c7e6 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpec.java @@ -0,0 +1,165 @@ +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.jeecgframework.poi.excel.annotation.Excel; +import org.springframework.format.annotation.DateTimeFormat; + +/** + * MES 混炼示方主表 + */ +@Data +@TableName("mes_xsl_mixing_spec") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "MES混炼示方") +public class MesXslMixingSpec implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Excel(name = "规格", width = 16) + @Schema(description = "规格") + private String specName; + + @Excel(name = "用途", width = 24) + @Schema(description = "用途") + private String purpose; + + @Schema(description = "机台ID") + private String machineId; + + @Excel(name = "机台", width = 14) + @Schema(description = "机台") + private String machineName; + + @Excel(name = "制作日期", width = 14, format = "yyyy-MM-dd") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @Schema(description = "制作日期") + private Date makeDate; + + @Excel(name = "发行编号", width = 16) + @Schema(description = "发行编号") + private String issueNumber; + + @Schema(description = "换算系数") + private BigDecimal convertFactor; + + @Schema(description = "填充体积") + private BigDecimal fillVolume; + + @Schema(description = "回收炭黑(秒)") + private Integer recycleCarbonSec; + + @Schema(description = "母胶比重") + private BigDecimal motherRubberSg; + + @Schema(description = "终炼胶比重") + private BigDecimal finalRubberSg; + + @Schema(description = "适用工厂") + private String applyFactory; + + @Schema(description = "段数") + private Integer stageCount; + + @Schema(description = "纯混炼时间(秒)") + private Integer pureMixSec; + + @Schema(description = "回收炭黑(KG)") + private BigDecimal recycleCarbonKg; + + @Schema(description = "自动小料打印设定") + private String autoSmallPrintSetting; + + @Schema(description = "设定车数") + private Integer setTrainCount; + + @Schema(description = "侧壁水温") + private BigDecimal sideWallWaterTemp; + + @Schema(description = "超时排胶时间") + private Integer overtimeDischargeSec; + + @Schema(description = "超温排胶时间") + private Integer overtempDischargeSec; + + @Schema(description = "超温排胶温度") + private BigDecimal overtempDischargeTemp; + + @Schema(description = "卸料门水温") + private BigDecimal doorWaterTemp; + + @Schema(description = "转子水温") + private BigDecimal rotorWaterTemp; + + @Schema(description = "最高进料温度") + private BigDecimal maxFeedTemp; + + @Schema(description = "起草人") + private String draftBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "起草时间") + private Date draftTime; + + @Schema(description = "校对人") + private String proofreadBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "校对时间") + private Date proofreadTime; + + @Schema(description = "审核人") + private String auditBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "审核时间") + private Date auditTime; + + @Schema(description = "批准人") + private String approveBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "批准时间") + private Date approveTime; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @Schema(description = "变更日期") + private Date changeDate; + + private String sysOrgCode; + 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; + + private Integer delFlag; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecDownStep.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecDownStep.java new file mode 100644 index 0000000..1126b91 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecDownStep.java @@ -0,0 +1,71 @@ +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 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; + +/** + * 混炼示方明细3:下密炼机混炼条件 + */ +@Data +@TableName("mes_xsl_mixing_spec_down_step") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "混炼示方下密炼机混炼条件") +public class MesXslMixingSpecDownStep implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Schema(description = "主表ID") + private String mixingSpecId; + + @Schema(description = "行序") + private Integer sortNo; + + @Schema(description = "动作") + private String actionName; + + @Schema(description = "时间(秒)") + private Integer actionSec; + + @Schema(description = "保护时间") + private Integer protectSec; + + @Schema(description = "温度(℃)") + private BigDecimal tempC; + + @Schema(description = "功率(Kw)") + private BigDecimal powerKw; + + @Schema(description = "能量(Kwh)") + private BigDecimal energyKwh; + + @Schema(description = "组合") + private String comboMode; + + @Schema(description = "转速(rpm)") + private BigDecimal speedRpm; + + @Schema(description = "压力(Mpa)") + private BigDecimal pressureMpa; + + @Schema(description = "栓(%)") + private BigDecimal boltPercent; + + @Schema(description = "租户ID") + private Integer tenantId; + + private String createBy; + private Date createTime; + private String updateBy; + private Date updateTime; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecMaterial.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecMaterial.java new file mode 100644 index 0000000..942c299 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecMaterial.java @@ -0,0 +1,65 @@ +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 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; + +/** + * 混炼示方明细1:橡胶及配合剂 + */ +@Data +@TableName("mes_xsl_mixing_spec_material") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "混炼示方橡胶及配合剂") +public class MesXslMixingSpecMaterial implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Schema(description = "主表ID") + private String mixingSpecId; + + @Schema(description = "行序") + private Integer sortNo; + + @Schema(description = "物料大类") + private String materialMajor; + + @Schema(description = "物料小类") + private String materialMinor; + + @Schema(description = "种类") + private String materialKind; + + @Schema(description = "密炼物料名称") + private String mixerMaterialName; + + @Schema(description = "密炼物料描述") + private String mixerMaterialDesc; + + @Schema(description = "单重") + private BigDecimal unitWeight; + + @Schema(description = "累计") + private BigDecimal accumWeight; + + @Schema(description = "顺序") + private Integer seqNo; + + @Schema(description = "租户ID") + private Integer tenantId; + + private String createBy; + private Date createTime; + private String updateBy; + private Date updateTime; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecStep.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecStep.java new file mode 100644 index 0000000..ead5e0c --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecStep.java @@ -0,0 +1,71 @@ +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 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; + +/** + * 混炼示方明细2:混合步骤 + */ +@Data +@TableName("mes_xsl_mixing_spec_step") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "混炼示方混合步骤") +public class MesXslMixingSpecStep implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Schema(description = "主表ID") + private String mixingSpecId; + + @Schema(description = "行序") + private Integer sortNo; + + @Schema(description = "动作") + private String actionName; + + @Schema(description = "时间(秒)") + private Integer actionSec; + + @Schema(description = "保护时间") + private Integer protectSec; + + @Schema(description = "温度(℃)") + private BigDecimal tempC; + + @Schema(description = "功率(Kw)") + private BigDecimal powerKw; + + @Schema(description = "能量(Kwh)") + private BigDecimal energyKwh; + + @Schema(description = "组合") + private String comboMode; + + @Schema(description = "转速(rpm)") + private BigDecimal speedRpm; + + @Schema(description = "压力(Mpa)") + private BigDecimal pressureMpa; + + @Schema(description = "栓(%)") + private BigDecimal boltPercent; + + @Schema(description = "租户ID") + private Integer tenantId; + + private String createBy; + private Date createTime; + private String updateBy; + private Date updateTime; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecTcu.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecTcu.java new file mode 100644 index 0000000..6db05b7 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecTcu.java @@ -0,0 +1,62 @@ +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 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; + +/** + * 混炼示方明细4:TCU温度条件 + */ +@Data +@TableName("mes_xsl_mixing_spec_tcu") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "混炼示方TCU温度条件") +public class MesXslMixingSpecTcu implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Schema(description = "主表ID") + private String mixingSpecId; + + @Schema(description = "行序") + private Integer sortNo; + + @Schema(description = "区分(字典xslmes_mixing_tcu_section)") + private String sectionType; + + @Schema(description = "前转子温度") + private BigDecimal frontRotorTemp; + + @Schema(description = "后转子温度") + private BigDecimal rearRotorTemp; + + @Schema(description = "前混炼室温度") + private BigDecimal frontChamberTemp; + + @Schema(description = "后混炼室温度") + private BigDecimal rearChamberTemp; + + @Schema(description = "上下顶栓温度") + private BigDecimal topPlugTemp; + + @Schema(description = "药品称量位置(字典xslmes_mixing_drug_weigh_pos)") + private String drugWeighPos; + + @Schema(description = "租户ID") + private Integer tenantId; + + private String createBy; + private Date createTime; + private String updateBy; + private Date updateTime; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecDownStepMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecDownStepMapper.java new file mode 100644 index 0000000..9dd1551 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecDownStepMapper.java @@ -0,0 +1,6 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecDownStep; + +public interface MesXslMixingSpecDownStepMapper extends BaseMapper {} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMapper.java new file mode 100644 index 0000000..e785fee --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMapper.java @@ -0,0 +1,6 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpec; + +public interface MesXslMixingSpecMapper extends BaseMapper {} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMaterialMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMaterialMapper.java new file mode 100644 index 0000000..396daeb --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMaterialMapper.java @@ -0,0 +1,6 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial; + +public interface MesXslMixingSpecMaterialMapper extends BaseMapper {} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecStepMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecStepMapper.java new file mode 100644 index 0000000..5294788 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecStepMapper.java @@ -0,0 +1,6 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecStep; + +public interface MesXslMixingSpecStepMapper extends BaseMapper {} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecTcuMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecTcuMapper.java new file mode 100644 index 0000000..154545e --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecTcuMapper.java @@ -0,0 +1,6 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecTcu; + +public interface MesXslMixingSpecTcuMapper extends BaseMapper {} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixingSpecService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixingSpecService.java new file mode 100644 index 0000000..4e6f857 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixingSpecService.java @@ -0,0 +1,39 @@ +package org.jeecg.modules.xslmes.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpec; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecDownStep; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecStep; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecTcu; +import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage; + +public interface IMesXslMixingSpecService extends IService { + void saveMain( + MesXslMixingSpec main, + List materialList, + List stepList, + List downStepList, + List tcuList); + + void updateMain( + MesXslMixingSpec main, + List materialList, + List stepList, + List downStepList, + List tcuList); + + void delMain(String id); + + void delBatchMain(Collection idList); + + MesXslMixingSpecPage queryPageById(String id); + + List> queryIssueNumberOptions(String keyword); + + List> queryPurposeOptions(String keyword); +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java new file mode 100644 index 0000000..f927a3d --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java @@ -0,0 +1,339 @@ +package org.jeecg.modules.xslmes.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpec; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecDownStep; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecStep; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecTcu; +import org.jeecg.modules.xslmes.mapper.MesXslMixingSpecDownStepMapper; +import org.jeecg.modules.xslmes.mapper.MesXslMixingSpecMapper; +import org.jeecg.modules.xslmes.mapper.MesXslMixingSpecMaterialMapper; +import org.jeecg.modules.xslmes.mapper.MesXslMixingSpecStepMapper; +import org.jeecg.modules.xslmes.mapper.MesXslMixingSpecTcuMapper; +import org.jeecg.modules.xslmes.service.IMesXslMixingSpecService; +import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +@Service +public class MesXslMixingSpecServiceImpl extends ServiceImpl + implements IMesXslMixingSpecService { + + private static final String TCU_UP = "up_mixer"; + private static final String TCU_DOWN = "down_mixer"; + + @Resource + private MesXslMixingSpecMaterialMapper materialMapper; + @Resource + private MesXslMixingSpecStepMapper stepMapper; + @Resource + private MesXslMixingSpecDownStepMapper downStepMapper; + @Resource + private MesXslMixingSpecTcuMapper tcuMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveMain( + MesXslMixingSpec main, + List materialList, + List stepList, + List downStepList, + List tcuList) { + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表新增保存----------- + normalizeMain(main); + this.save(main); + saveChildren(main.getId(), materialList, stepList, downStepList, tcuList); + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表新增保存----------- + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateMain( + MesXslMixingSpec main, + List materialList, + List stepList, + List downStepList, + List tcuList) { + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表编辑保存----------- + normalizeMain(main); + this.updateById(main); + clearChildren(main.getId()); + saveChildren(main.getId(), materialList, stepList, downStepList, tcuList); + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表编辑保存----------- + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delMain(String id) { + clearChildren(id); + this.removeById(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delBatchMain(Collection idList) { + if (CollectionUtils.isEmpty(idList)) { + return; + } + for (Serializable id : idList) { + if (id != null) { + delMain(String.valueOf(id)); + } + } + } + + @Override + public MesXslMixingSpecPage queryPageById(String id) { + MesXslMixingSpec main = this.getById(id); + if (main == null) { + return null; + } + MesXslMixingSpecPage page = new MesXslMixingSpecPage(); + page.setId(main.getId()); + page.setTenantId(main.getTenantId()); + page.setSpecName(main.getSpecName()); + page.setPurpose(main.getPurpose()); + page.setMachineId(main.getMachineId()); + page.setMachineName(main.getMachineName()); + page.setMakeDate(main.getMakeDate()); + page.setIssueNumber(main.getIssueNumber()); + page.setConvertFactor(main.getConvertFactor()); + page.setFillVolume(main.getFillVolume()); + page.setRecycleCarbonSec(main.getRecycleCarbonSec()); + page.setMotherRubberSg(main.getMotherRubberSg()); + page.setFinalRubberSg(main.getFinalRubberSg()); + page.setApplyFactory(main.getApplyFactory()); + page.setStageCount(main.getStageCount()); + page.setPureMixSec(main.getPureMixSec()); + page.setRecycleCarbonKg(main.getRecycleCarbonKg()); + page.setAutoSmallPrintSetting(main.getAutoSmallPrintSetting()); + page.setSetTrainCount(main.getSetTrainCount()); + page.setSideWallWaterTemp(main.getSideWallWaterTemp()); + page.setOvertimeDischargeSec(main.getOvertimeDischargeSec()); + page.setOvertempDischargeSec(main.getOvertempDischargeSec()); + page.setOvertempDischargeTemp(main.getOvertempDischargeTemp()); + page.setDoorWaterTemp(main.getDoorWaterTemp()); + page.setRotorWaterTemp(main.getRotorWaterTemp()); + page.setMaxFeedTemp(main.getMaxFeedTemp()); + page.setDraftBy(main.getDraftBy()); + page.setDraftTime(main.getDraftTime()); + page.setProofreadBy(main.getProofreadBy()); + page.setProofreadTime(main.getProofreadTime()); + page.setAuditBy(main.getAuditBy()); + page.setAuditTime(main.getAuditTime()); + page.setApproveBy(main.getApproveBy()); + page.setApproveTime(main.getApproveTime()); + page.setChangeDate(main.getChangeDate()); + page.setSysOrgCode(main.getSysOrgCode()); + page.setCreateBy(main.getCreateBy()); + page.setCreateTime(main.getCreateTime()); + page.setUpdateBy(main.getUpdateBy()); + page.setUpdateTime(main.getUpdateTime()); + page.setDelFlag(main.getDelFlag()); + + page.setMaterialList(queryMaterialByMainId(id)); + page.setStepList(queryStepByMainId(id)); + page.setDownStepList(queryDownStepByMainId(id)); + page.setTcuList(fillDefaultTcuRows(queryTcuByMainId(id))); + return page; + } + + @Override + public List> queryIssueNumberOptions(String keyword) { + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】发行编号联想取密炼PS----------- + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if (StringUtils.isNotBlank(keyword)) { + queryWrapper.like(MesXslMixingSpec::getIssueNumber, keyword); + } + queryWrapper.isNotNull(MesXslMixingSpec::getIssueNumber) + .orderByDesc(MesXslMixingSpec::getUpdateTime) + .orderByDesc(MesXslMixingSpec::getCreateTime) + .last("limit 30"); + List rows = this.list(queryWrapper); + List> options = new ArrayList<>(); + for (MesXslMixingSpec row : rows) { + if (StringUtils.isBlank(row.getIssueNumber())) { + continue; + } + options.add(Map.of("label", row.getIssueNumber(), "value", row.getIssueNumber())); + } + return options; + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】发行编号联想取密炼PS----------- + } + + @Override + public List> queryPurposeOptions(String keyword) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if (StringUtils.isNotBlank(keyword)) { + queryWrapper.like(MesXslMixingSpec::getPurpose, keyword); + } + queryWrapper.isNotNull(MesXslMixingSpec::getPurpose) + .orderByDesc(MesXslMixingSpec::getUpdateTime) + .orderByDesc(MesXslMixingSpec::getCreateTime) + .last("limit 50"); + List rows = this.list(queryWrapper); + List> options = new ArrayList<>(); + for (MesXslMixingSpec row : rows) { + if (StringUtils.isBlank(row.getPurpose())) { + continue; + } + options.add(Map.of("label", row.getPurpose(), "value", row.getPurpose())); + } + return options; + } + + private void normalizeMain(MesXslMixingSpec main) { + if (main.getDraftTime() == null) { + main.setDraftTime(new Date()); + } + if (main.getDelFlag() == null) { + main.setDelFlag(0); + } + } + + private void clearChildren(String mainId) { + materialMapper.delete(new LambdaQueryWrapper().eq(MesXslMixingSpecMaterial::getMixingSpecId, mainId)); + stepMapper.delete(new LambdaQueryWrapper().eq(MesXslMixingSpecStep::getMixingSpecId, mainId)); + downStepMapper.delete(new LambdaQueryWrapper().eq(MesXslMixingSpecDownStep::getMixingSpecId, mainId)); + tcuMapper.delete(new LambdaQueryWrapper().eq(MesXslMixingSpecTcu::getMixingSpecId, mainId)); + } + + private void saveChildren( + String mainId, + List materialList, + List stepList, + List downStepList, + List tcuList) { + Date now = new Date(); + int sort = 0; + if (!CollectionUtils.isEmpty(materialList)) { + for (MesXslMixingSpecMaterial row : materialList) { + if (row == null) { + continue; + } + row.setId(null); + row.setMixingSpecId(mainId); + row.setSortNo(sort++); + if (row.getCreateTime() == null) { + row.setCreateTime(now); + } + materialMapper.insert(row); + } + } + sort = 0; + if (!CollectionUtils.isEmpty(stepList)) { + for (MesXslMixingSpecStep row : stepList) { + if (row == null) { + continue; + } + row.setId(null); + row.setMixingSpecId(mainId); + row.setSortNo(sort++); + if (row.getCreateTime() == null) { + row.setCreateTime(now); + } + stepMapper.insert(row); + } + } + sort = 0; + if (!CollectionUtils.isEmpty(downStepList)) { + for (MesXslMixingSpecDownStep row : downStepList) { + if (row == null) { + continue; + } + row.setId(null); + row.setMixingSpecId(mainId); + row.setSortNo(sort++); + if (row.getCreateTime() == null) { + row.setCreateTime(now); + } + downStepMapper.insert(row); + } + } + List tcuRows = fillDefaultTcuRows(tcuList); + sort = 0; + for (MesXslMixingSpecTcu row : tcuRows) { + row.setId(null); + row.setMixingSpecId(mainId); + row.setSortNo(sort++); + if (row.getCreateTime() == null) { + row.setCreateTime(now); + } + if (TCU_DOWN.equals(row.getSectionType())) { + row.setDrugWeighPos(null); + } + tcuMapper.insert(row); + } + } + + private List queryMaterialByMainId(String mainId) { + return materialMapper.selectList( + new LambdaQueryWrapper() + .eq(MesXslMixingSpecMaterial::getMixingSpecId, mainId) + .orderByAsc(MesXslMixingSpecMaterial::getSortNo) + .orderByAsc(MesXslMixingSpecMaterial::getId)); + } + + private List queryStepByMainId(String mainId) { + return stepMapper.selectList( + new LambdaQueryWrapper() + .eq(MesXslMixingSpecStep::getMixingSpecId, mainId) + .orderByAsc(MesXslMixingSpecStep::getSortNo) + .orderByAsc(MesXslMixingSpecStep::getId)); + } + + private List queryDownStepByMainId(String mainId) { + return downStepMapper.selectList( + new LambdaQueryWrapper() + .eq(MesXslMixingSpecDownStep::getMixingSpecId, mainId) + .orderByAsc(MesXslMixingSpecDownStep::getSortNo) + .orderByAsc(MesXslMixingSpecDownStep::getId)); + } + + private List queryTcuByMainId(String mainId) { + return tcuMapper.selectList( + new LambdaQueryWrapper() + .eq(MesXslMixingSpecTcu::getMixingSpecId, mainId) + .orderByAsc(MesXslMixingSpecTcu::getSortNo) + .orderByAsc(MesXslMixingSpecTcu::getId)); + } + + private List fillDefaultTcuRows(List source) { + List rows = new ArrayList<>(); + if (!CollectionUtils.isEmpty(source)) { + rows.addAll(source); + } + boolean hasUp = rows.stream().anyMatch(r -> TCU_UP.equals(r.getSectionType())); + boolean hasDown = rows.stream().anyMatch(r -> TCU_DOWN.equals(r.getSectionType())); + if (!hasUp) { + MesXslMixingSpecTcu up = new MesXslMixingSpecTcu(); + up.setSectionType(TCU_UP); + rows.add(0, up); + } + if (!hasDown) { + MesXslMixingSpecTcu down = new MesXslMixingSpecTcu(); + down.setSectionType(TCU_DOWN); + rows.add(down); + } + rows.sort((a, b) -> { + int ai = TCU_UP.equals(a.getSectionType()) ? 0 : TCU_DOWN.equals(a.getSectionType()) ? 1 : 2; + int bi = TCU_UP.equals(b.getSectionType()) ? 0 : TCU_DOWN.equals(b.getSectionType()) ? 1 : 2; + return Integer.compare(ai, bi); + }); + if (rows.size() > 2) { + return new ArrayList<>(rows.subList(0, 2)); + } + return rows; + } +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslMixingSpecPage.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslMixingSpecPage.java new file mode 100644 index 0000000..ba4b919 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslMixingSpecPage.java @@ -0,0 +1,22 @@ +package org.jeecg.modules.xslmes.vo; + +import java.util.List; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpec; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecDownStep; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecStep; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecTcu; + +/** + * 混炼示方主子保存VO + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class MesXslMixingSpecPage extends MesXslMixingSpec { + private List materialList; + private List stepList; + private List downStepList; + private List tcuList; +} diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_98__mes_xsl_mixing_spec.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_98__mes_xsl_mixing_spec.sql new file mode 100644 index 0000000..b96e8eb --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_98__mes_xsl_mixing_spec.sql @@ -0,0 +1,195 @@ +SET NAMES utf8mb4; + +INSERT IGNORE INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`) +VALUES ('1995000000000000098', '混炼TCU区分', 'xslmes_mixing_tcu_section', '混炼示方TCU区分', 0, 'admin', NOW(), 0, 1002); + +INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`) +VALUES ('1995000000000009801', '1995000000000000098', '上密炼机', 'up_mixer', 1, 1, 'admin', NOW()); +INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`) +VALUES ('1995000000000009802', '1995000000000000098', '下密炼机', 'down_mixer', 2, 1, 'admin', NOW()); + +INSERT IGNORE INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`) +VALUES ('1995000000000000099', '混炼药品称量位置', 'xslmes_mixing_drug_weigh_pos', '混炼示方药品称量位置', 0, 'admin', NOW(), 0, 1002); + +INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`) +VALUES ('1995000000000009901', '1995000000000000099', '药品称', 'drug_scale', 1, 1, 'admin', NOW()); +INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`) +VALUES ('1995000000000009902', '1995000000000000099', '胶料称', 'rubber_scale', 2, 1, 'admin', NOW()); + +CREATE TABLE IF NOT EXISTS `mes_xsl_mixing_spec` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `tenant_id` int DEFAULT NULL COMMENT '租户ID', + `spec_name` varchar(120) DEFAULT NULL COMMENT '规格', + `purpose` varchar(300) DEFAULT NULL COMMENT '用途', + `machine_id` varchar(32) DEFAULT NULL COMMENT '机台ID', + `machine_name` varchar(120) DEFAULT NULL COMMENT '机台', + `make_date` date DEFAULT NULL COMMENT '制作日期', + `issue_number` varchar(120) DEFAULT NULL COMMENT '发行编号', + `convert_factor` decimal(18,6) DEFAULT NULL COMMENT '换算系数', + `fill_volume` decimal(18,6) DEFAULT NULL COMMENT '填充体积', + `recycle_carbon_sec` int DEFAULT NULL COMMENT '回收炭黑(秒)', + `mother_rubber_sg` decimal(18,6) DEFAULT NULL COMMENT '母胶比重', + `final_rubber_sg` decimal(18,6) DEFAULT NULL COMMENT '终炼胶比重', + `apply_factory` varchar(120) DEFAULT NULL COMMENT '适用工厂', + `stage_count` int DEFAULT NULL COMMENT '段数', + `pure_mix_sec` int DEFAULT NULL COMMENT '纯混炼时间(秒)', + `recycle_carbon_kg` decimal(18,6) DEFAULT NULL COMMENT '回收炭黑(KG)', + `auto_small_print_setting` varchar(200) DEFAULT NULL COMMENT '自动小料打印设定', + `set_train_count` int DEFAULT NULL COMMENT '设定车数', + `side_wall_water_temp` decimal(18,6) DEFAULT NULL COMMENT '侧壁水温', + `overtime_discharge_sec` int DEFAULT NULL COMMENT '超时排胶时间', + `overtemp_discharge_sec` int DEFAULT NULL COMMENT '超温排胶时间', + `overtemp_discharge_temp` decimal(18,6) DEFAULT NULL COMMENT '超温排胶温度', + `door_water_temp` decimal(18,6) DEFAULT NULL COMMENT '卸料门水温', + `rotor_water_temp` decimal(18,6) DEFAULT NULL COMMENT '转子水温', + `max_feed_temp` decimal(18,6) DEFAULT NULL COMMENT '最高进料温度', + `draft_by` varchar(80) DEFAULT NULL COMMENT '起草人', + `draft_time` datetime DEFAULT NULL COMMENT '起草时间', + `proofread_by` varchar(80) DEFAULT NULL COMMENT '校对人', + `proofread_time` datetime DEFAULT NULL COMMENT '校对时间', + `audit_by` varchar(80) DEFAULT NULL COMMENT '审核人', + `audit_time` datetime DEFAULT NULL COMMENT '审核时间', + `approve_by` varchar(80) DEFAULT NULL COMMENT '批准人', + `approve_time` datetime DEFAULT NULL COMMENT '批准时间', + `change_date` date DEFAULT NULL COMMENT '变更日期', + `sys_org_code` varchar(64) DEFAULT NULL COMMENT '所属部门', + `create_by` varchar(50) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(50) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `del_flag` int NOT NULL DEFAULT 0 COMMENT '逻辑删除', + PRIMARY KEY (`id`), + KEY `idx_mxmix_issue_number` (`issue_number`), + KEY `idx_mxmix_spec_name` (`spec_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES混炼示方'; + +CREATE TABLE IF NOT EXISTS `mes_xsl_mixing_spec_material` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `mixing_spec_id` varchar(32) NOT NULL COMMENT '混炼示方主表ID', + `sort_no` int DEFAULT NULL COMMENT '行序号', + `material_major` varchar(120) DEFAULT NULL COMMENT '物料大类', + `material_minor` varchar(120) DEFAULT NULL COMMENT '物料小类', + `material_kind` varchar(120) DEFAULT NULL COMMENT '种类', + `mixer_material_name` varchar(200) DEFAULT NULL COMMENT '密炼物料名称', + `mixer_material_desc` varchar(300) DEFAULT NULL COMMENT '密炼物料描述', + `unit_weight` decimal(18,6) DEFAULT NULL COMMENT '单重', + `accum_weight` decimal(18,6) DEFAULT NULL COMMENT '累计', + `seq_no` int DEFAULT NULL COMMENT '顺序', + `tenant_id` int DEFAULT NULL COMMENT '租户ID', + `create_by` varchar(50) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(50) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_mxmix_mat_main` (`mixing_spec_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES混炼示方明细-橡胶及配合剂'; + +CREATE TABLE IF NOT EXISTS `mes_xsl_mixing_spec_step` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `mixing_spec_id` varchar(32) NOT NULL COMMENT '混炼示方主表ID', + `sort_no` int DEFAULT NULL COMMENT '行序号', + `action_name` varchar(120) DEFAULT NULL COMMENT '动作', + `action_sec` int DEFAULT NULL COMMENT '时间(秒)', + `protect_sec` int DEFAULT NULL COMMENT '保护时间', + `temp_c` decimal(18,6) DEFAULT NULL COMMENT '温度(℃)', + `power_kw` decimal(18,6) DEFAULT NULL COMMENT '功率(Kw)', + `energy_kwh` decimal(18,6) DEFAULT NULL COMMENT '能量(Kwh)', + `combo_mode` varchar(120) DEFAULT NULL COMMENT '组合', + `speed_rpm` decimal(18,6) DEFAULT NULL COMMENT '转速(rpm)', + `pressure_mpa` decimal(18,6) DEFAULT NULL COMMENT '压力(Mpa)', + `bolt_percent` decimal(18,6) DEFAULT NULL COMMENT '栓(%)', + `tenant_id` int DEFAULT NULL COMMENT '租户ID', + `create_by` varchar(50) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(50) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_mxmix_step_main` (`mixing_spec_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES混炼示方明细-混合步骤'; + +CREATE TABLE IF NOT EXISTS `mes_xsl_mixing_spec_down_step` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `mixing_spec_id` varchar(32) NOT NULL COMMENT '混炼示方主表ID', + `sort_no` int DEFAULT NULL COMMENT '行序号', + `action_name` varchar(120) DEFAULT NULL COMMENT '动作', + `action_sec` int DEFAULT NULL COMMENT '时间(秒)', + `protect_sec` int DEFAULT NULL COMMENT '保护时间', + `temp_c` decimal(18,6) DEFAULT NULL COMMENT '温度(℃)', + `power_kw` decimal(18,6) DEFAULT NULL COMMENT '功率(Kw)', + `energy_kwh` decimal(18,6) DEFAULT NULL COMMENT '能量(Kwh)', + `combo_mode` varchar(120) DEFAULT NULL COMMENT '组合', + `speed_rpm` decimal(18,6) DEFAULT NULL COMMENT '转速(rpm)', + `pressure_mpa` decimal(18,6) DEFAULT NULL COMMENT '压力(Mpa)', + `bolt_percent` decimal(18,6) DEFAULT NULL COMMENT '栓(%)', + `tenant_id` int DEFAULT NULL COMMENT '租户ID', + `create_by` varchar(50) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(50) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_mxmix_down_step_main` (`mixing_spec_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES混炼示方明细-下密炼机混炼条件'; + +CREATE TABLE IF NOT EXISTS `mes_xsl_mixing_spec_tcu` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `mixing_spec_id` varchar(32) NOT NULL COMMENT '混炼示方主表ID', + `sort_no` int DEFAULT NULL COMMENT '行序号', + `section_type` varchar(32) DEFAULT NULL COMMENT '区分(上密炼机/下密炼机)', + `front_rotor_temp` decimal(18,6) DEFAULT NULL COMMENT '前转子温度', + `rear_rotor_temp` decimal(18,6) DEFAULT NULL COMMENT '后转子温度', + `front_chamber_temp` decimal(18,6) DEFAULT NULL COMMENT '前混炼室温度', + `rear_chamber_temp` decimal(18,6) DEFAULT NULL COMMENT '后混炼室温度', + `top_plug_temp` decimal(18,6) DEFAULT NULL COMMENT '上下顶栓温度', + `drug_weigh_pos` varchar(32) DEFAULT NULL COMMENT '药品称量位置', + `tenant_id` int DEFAULT NULL COMMENT '租户ID', + `create_by` varchar(50) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(50) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_mxmix_tcu_main` (`mixing_spec_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES混炼示方明细-TCU温度条件'; + +UPDATE `sys_permission` +SET `is_leaf` = 0, `update_time` = NOW() +WHERE `id` = '1900000000000000810' AND `is_leaf` = 1; + +INSERT IGNORE INTO `sys_permission` ( + `id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, + `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, + `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, + `del_flag`, `rule_flag`, `status`, `internal_or_external` +) VALUES ( + '177925970995540', '1900000000000000810', '混炼示方', '/xslmes/mesXslMixingSpec', + 'xslmes/mesXslMixingSpec/MesXslMixingSpecList', 1, 'MesXslMixingSpecList', NULL, + 1, NULL, '0', 2.00, 0, 'ant-design:table-outlined', 0, 1, + 0, 0, 'MES混炼示方', 'admin', NOW(), 'admin', NOW(), + 0, 0, '1', 0 +); + +INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +VALUES ('177925970995541', '177925970995540', '新增', 2, 'xslmes:mes_xsl_mixing_spec:add', '1', 1.00, 0, 1, 0, '1', 0, 'admin', NOW()); +INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +VALUES ('177925970995542', '177925970995540', '编辑', 2, 'xslmes:mes_xsl_mixing_spec:edit', '1', 2.00, 0, 1, 0, '1', 0, 'admin', NOW()); +INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +VALUES ('177925970995543', '177925970995540', '删除', 2, 'xslmes:mes_xsl_mixing_spec:delete', '1', 3.00, 0, 1, 0, '1', 0, 'admin', NOW()); +INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +VALUES ('177925970995544', '177925970995540', '批量删除', 2, 'xslmes:mes_xsl_mixing_spec:deleteBatch', '1', 4.00, 0, 1, 0, '1', 0, 'admin', NOW()); +INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +VALUES ('177925970995545', '177925970995540', '导出', 2, 'xslmes:mes_xsl_mixing_spec:exportXls', '1', 5.00, 0, 1, 0, '1', 0, 'admin', NOW()); +INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +VALUES ('177925970995546', '177925970995540', '导入', 2, 'xslmes:mes_xsl_mixing_spec:importExcel', '1', 6.00, 0, 1, 0, '1', 0, 'admin', NOW()); + +INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`) +SELECT REPLACE(UUID(), '-', ''), r.id, p.id, NULL, NOW(), '127.0.0.1' +FROM `sys_role` r +CROSS JOIN `sys_permission` p +WHERE r.`role_code` = 'admin' + AND p.`id` IN ( + '177925970995540', '177925970995541', '177925970995542', + '177925970995543', '177925970995544', '177925970995545', '177925970995546' + ) + AND NOT EXISTS ( + SELECT 1 FROM `sys_role_permission` rp + WHERE rp.`role_id` = r.id AND rp.`permission_id` = p.id + ); diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts new file mode 100644 index 0000000..328081e --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts @@ -0,0 +1,37 @@ +import { defHttp } from '/@/utils/http/axios'; +import { Modal } from 'ant-design-vue'; + +enum Api { + list = '/xslmes/mesXslMixingSpec/list', + save = '/xslmes/mesXslMixingSpec/add', + edit = '/xslmes/mesXslMixingSpec/edit', + deleteOne = '/xslmes/mesXslMixingSpec/delete', + deleteBatch = '/xslmes/mesXslMixingSpec/deleteBatch', + importExcel = '/xslmes/mesXslMixingSpec/importExcel', + exportXls = '/xslmes/mesXslMixingSpec/exportXls', + queryById = '/xslmes/mesXslMixingSpec/queryById', + queryIssueNumberOptions = '/xslmes/mesXslMixingSpec/queryIssueNumberOptions', + queryPurposeOptions = '/xslmes/mesXslMixingSpec/queryPurposeOptions', +} + +export const getExportUrl = Api.exportXls; +export const getImportUrl = Api.importExcel; +export const list = (params) => defHttp.get({ url: Api.list, params }); +export const queryById = (params) => defHttp.get({ url: Api.queryById, params }); +export const saveOrUpdate = (params, isUpdate) => defHttp.post({ url: isUpdate ? Api.edit : Api.save, params }); +export const queryIssueNumberOptions = (params) => defHttp.get({ url: Api.queryIssueNumberOptions, params }); +export const queryPurposeOptions = (params) => defHttp.get({ url: Api.queryPurposeOptions, params }); + +export const deleteOne = (params, handleSuccess) => + defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => handleSuccess()); + +export const batchDelete = (params, handleSuccess) => { + Modal.confirm({ + title: '确认删除', + content: '是否删除选中数据', + okText: '确认', + cancelText: '取消', + onOk: () => + defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => handleSuccess()), + }); +}; diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts new file mode 100644 index 0000000..e9e089e --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts @@ -0,0 +1,587 @@ +import { BasicColumn, FormSchema } from '/@/components/Table'; +import { JVxeColumn, JVxeTypes } from '/@/components/jeecg/JVxeTable/types'; +import { createLocalStorage } from '/@/utils/cache'; +import { buildUUID } from '/@/utils/uuid'; + +const mixingMaterialColumnStorage = createLocalStorage(); + +/** 橡胶及配合剂明细列隐藏偏好 localStorage 键 */ +export const MIXING_MATERIAL_COLUMN_CACHE_KEY = 'mes_xsl_mixing_spec_material_hidden_columns'; + +/** 橡胶及配合剂明细列宽偏好 localStorage 键 */ +export const MIXING_MATERIAL_COLUMN_WIDTH_CACHE_KEY = 'mes_xsl_mixing_spec_material_column_widths_v2'; + +/** 行号列宽度(与 JVxeTable rowNumber 默认一致) */ +export const MIXING_MATERIAL_ROW_NUMBER_WIDTH = 60; + +/** 橡胶及配合剂明细列可缩小到的最小宽度 */ +export const MIXING_MATERIAL_MIN_COLUMN_WIDTH = 40; + +/** 默认隐藏的明细列 */ +export const MIXING_MATERIAL_DEFAULT_HIDDEN_COLUMN_KEYS = ['materialMajor', 'materialKind']; + +/** 不允许隐藏的明细列 */ +export const MIXING_MATERIAL_LOCKED_COLUMN_KEYS = ['mixerMaterialName']; + +export interface MixingMaterialColumnSettingItem { + key: string; + title: string; + locked?: boolean; +} + +export const columns: BasicColumn[] = [ + { title: '规格', align: 'center', dataIndex: 'specName', width: 160, fixed: 'left' }, + { title: '用途', align: 'center', dataIndex: 'purpose', width: 180 }, + { title: '机台', align: 'center', dataIndex: 'machineName', width: 120 }, + { title: '制作日期', align: 'center', dataIndex: 'makeDate', width: 120 }, + { title: '发行编号', align: 'center', dataIndex: 'issueNumber', width: 150 }, + { title: '段数', align: 'center', dataIndex: 'stageCount', width: 80 }, + { title: '纯混炼时间(秒)', align: 'center', dataIndex: 'pureMixSec', width: 130 }, + { title: '变更日期', align: 'center', dataIndex: 'changeDate', width: 120 }, + { title: '修改时间', align: 'center', dataIndex: 'updateTime', width: 165 }, +]; + +export const searchFormSchema: FormSchema[] = [ + { label: '关键字', field: 'keyword', component: 'Input', colProps: { span: 8 }, componentProps: { placeholder: '规格/用途/发行编号/机台' } }, + { label: '制作日期起', field: 'makeDate_begin', component: 'DatePicker', colProps: { span: 8 }, componentProps: { valueFormat: 'YYYY-MM-DD' } }, + { label: '制作日期止', field: 'makeDate_end', component: 'DatePicker', colProps: { span: 8 }, componentProps: { valueFormat: 'YYYY-MM-DD' } }, +]; + +export const mainSchema: FormSchema[] = [ + { label: '', field: 'id', component: 'Input', show: false }, + { label: '规格', field: 'specName', component: 'Input', required: true, colProps: { span: 8 } }, + { label: '用途', field: 'purpose', component: 'AutoComplete', required: true, colProps: { span: 8 } }, + { label: '机台', field: 'machineName', component: 'Input', colProps: { span: 8 } }, + { label: '制作日期', field: 'makeDate', component: 'DatePicker', colProps: { span: 8 }, componentProps: { valueFormat: 'YYYY-MM-DD' } }, + { label: '发行编号', field: 'issueNumber', component: 'AutoComplete', required: true, colProps: { span: 8 } }, + { label: '换算系数', field: 'convertFactor', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, + { label: '填充体积', field: 'fillVolume', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, + { label: '回收炭黑(秒)', field: 'recycleCarbonSec', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } }, + { label: '母胶比重', field: 'motherRubberSg', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, + { label: '终炼胶比重', field: 'finalRubberSg', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, + { label: '适用工厂', field: 'applyFactory', component: 'Input', colProps: { span: 8 } }, + { label: '段数', field: 'stageCount', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } }, + { label: '纯混炼时间(秒)', field: 'pureMixSec', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } }, + { label: '回收炭黑(KG)', field: 'recycleCarbonKg', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, + { label: '自动小料打印设定', field: 'autoSmallPrintSetting', component: 'Input', colProps: { span: 8 } }, + { label: '设定车数', field: 'setTrainCount', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } }, + { label: '侧壁水温', field: 'sideWallWaterTemp', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, + { label: '超时排胶时间', field: 'overtimeDischargeSec', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } }, + { label: '超温排胶时间', field: 'overtempDischargeSec', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } }, + { label: '超温排胶温度', field: 'overtempDischargeTemp', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, + { label: '卸料门水温', field: 'doorWaterTemp', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, + { label: '转子水温', field: 'rotorWaterTemp', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, + { label: '最高进料温度', field: 'maxFeedTemp', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, + { label: '起草人', field: 'draftBy', component: 'Input', colProps: { span: 8 } }, + { label: '起草时间', field: 'draftTime', component: 'DatePicker', colProps: { span: 8 }, componentProps: { showTime: true, valueFormat: 'YYYY-MM-DD HH:mm:ss' } }, + { label: '校对人', field: 'proofreadBy', component: 'Input', colProps: { span: 8 } }, + { label: '校对时间', field: 'proofreadTime', component: 'DatePicker', colProps: { span: 8 }, componentProps: { showTime: true, valueFormat: 'YYYY-MM-DD HH:mm:ss' } }, + { label: '审核人', field: 'auditBy', component: 'Input', colProps: { span: 8 } }, + { label: '审核时间', field: 'auditTime', component: 'DatePicker', colProps: { span: 8 }, componentProps: { showTime: true, valueFormat: 'YYYY-MM-DD HH:mm:ss' } }, + { label: '批准人', field: 'approveBy', component: 'Input', colProps: { span: 8 } }, + { label: '批准时间', field: 'approveTime', component: 'DatePicker', colProps: { span: 8 }, componentProps: { showTime: true, valueFormat: 'YYYY-MM-DD HH:mm:ss' } }, + { label: '变更日期', field: 'changeDate', component: 'DatePicker', colProps: { span: 8 }, componentProps: { valueFormat: 'YYYY-MM-DD' } }, +]; + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】橡胶及配合剂明细列展示设置----------- +export const materialColumns: JVxeColumn[] = [ + { title: '物料大类', key: 'materialMajor', type: JVxeTypes.input, width: 100, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH }, + { title: '物料小类', key: 'materialMinor', type: JVxeTypes.input, width: 120, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH }, + { title: '种类', key: 'materialKind', type: JVxeTypes.input, width: 80, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH }, + { title: '密炼物料名称', key: 'mixerMaterialName', type: JVxeTypes.input, width: 160, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH }, + { title: '密炼物料描述', key: 'mixerMaterialDesc', type: JVxeTypes.input, width: 220, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH }, + { title: '单重', key: 'unitWeight', type: JVxeTypes.inputNumber, width: 72, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '累计', key: 'accumWeight', type: JVxeTypes.inputNumber, width: 72, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '顺序', key: 'seqNo', type: JVxeTypes.inputNumber, width: 64, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, align: 'center' }, +]; + +/** 橡胶及配合剂明细列设置项 */ +export function getMixingMaterialColumnSettingItems(): MixingMaterialColumnSettingItem[] { + return materialColumns.map((col) => ({ + key: String(col.key), + title: String(col.title), + locked: MIXING_MATERIAL_LOCKED_COLUMN_KEYS.includes(String(col.key)), + })); +} + +/** 读取已隐藏的橡胶及配合剂明细列 key */ +export function loadMixingMaterialHiddenColumnKeys(): string[] { + const saved = mixingMaterialColumnStorage.get(MIXING_MATERIAL_COLUMN_CACHE_KEY); + const validKeys = new Set(getMixingMaterialColumnSettingItems().map((item) => item.key)); + if (!Array.isArray(saved)) { + return MIXING_MATERIAL_DEFAULT_HIDDEN_COLUMN_KEYS.filter((key) => validKeys.has(key)); + } + return saved.filter( + (key) => typeof key === 'string' && !MIXING_MATERIAL_LOCKED_COLUMN_KEYS.includes(key) && validKeys.has(key), + ); +} + +/** 保存已隐藏的橡胶及配合剂明细列 key */ +export function saveMixingMaterialHiddenColumnKeys(hiddenKeys: string[]) { + const validKeys = hiddenKeys.filter((key) => !MIXING_MATERIAL_LOCKED_COLUMN_KEYS.includes(key)); + if (validKeys.length) { + mixingMaterialColumnStorage.set(MIXING_MATERIAL_COLUMN_CACHE_KEY, validKeys); + return; + } + mixingMaterialColumnStorage.remove(MIXING_MATERIAL_COLUMN_CACHE_KEY); +} + +/** 按隐藏配置过滤橡胶及配合剂明细列 */ +export function applyMixingMaterialColumnVisibility(columns: JVxeColumn[], hiddenKeys: string[]): JVxeColumn[] { + if (!hiddenKeys?.length) { + return columns; + } + const hiddenSet = new Set(hiddenKeys); + return columns.filter((col) => !col.key || !hiddenSet.has(String(col.key))); +} + +/** 读取已保存的橡胶及配合剂明细列宽 */ +export function loadMixingMaterialColumnWidths(): Record { + const saved = mixingMaterialColumnStorage.get(MIXING_MATERIAL_COLUMN_WIDTH_CACHE_KEY); + const validKeys = new Set(materialColumns.map((col) => String(col.key))); + if (!saved || typeof saved !== 'object') { + return {}; + } + const result: Record = {}; + Object.entries(saved as Record).forEach(([key, value]) => { + if (validKeys.has(key) && typeof value === 'number' && value > 0) { + result[key] = value; + } + }); + return result; +} + +/** 保存橡胶及配合剂明细列宽 */ +export function saveMixingMaterialColumnWidths(widthMap: Record) { + const validKeys = new Set(materialColumns.map((col) => String(col.key))); + const next: Record = {}; + Object.entries(widthMap || {}).forEach(([key, value]) => { + if (validKeys.has(key) && typeof value === 'number' && value > 0) { + next[key] = value; + } + }); + if (Object.keys(next).length) { + mixingMaterialColumnStorage.set(MIXING_MATERIAL_COLUMN_WIDTH_CACHE_KEY, next); + return; + } + mixingMaterialColumnStorage.remove(MIXING_MATERIAL_COLUMN_WIDTH_CACHE_KEY); +} + +/** 应用已保存列宽(minWidth 保持最小值,允许拖拽缩小) */ +export function applyMixingMaterialColumnWidths(columns: JVxeColumn[], widthMap: Record): JVxeColumn[] { + return columns.map((col) => { + const savedWidth = widthMap[String(col.key)]; + const nextCol = { + ...col, + minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, + }; + if (savedWidth) { + nextCol.width = savedWidth; + } + return nextCol; + }); +} + +/** 计算橡胶及配合剂明细表总宽度 */ +export function calcMixingMaterialTableWidth(columns: JVxeColumn[], widthMap: Record = {}) { + const dataWidth = columns.reduce((sum, col) => { + const key = String(col.key); + const width = widthMap[key] ?? Number(col.width) ?? 80; + return sum + width; + }, 0); + return MIXING_MATERIAL_ROW_NUMBER_WIDTH + dataWidth + 1; +} +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】橡胶及配合剂明细列展示设置----------- + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A20】明细表默认列宽对齐参考图----------- +/** 混合步骤/下密炼机明细列可缩小到的最小宽度 */ +export const MIXING_STEP_MIN_COLUMN_WIDTH = 48; + +export const stepColumns: JVxeColumn[] = [ + { title: '动作', key: 'actionName', type: JVxeTypes.input, width: 120, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH }, + { title: '时间(")', key: 'actionSec', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '保护时间', key: 'protectSec', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '温度(℃)', key: 'tempC', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '功率(Kw)', key: 'powerKw', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '能量(Kwh)', key: 'energyKwh', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '组合', key: 'comboMode', type: JVxeTypes.input, width: 72, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '转速(rpm)', key: 'speedRpm', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '压力(Mpa)', key: 'pressureMpa', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '栓(%)', key: 'boltPercent', type: JVxeTypes.inputNumber, width: 72, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, +]; + +/** 混合步骤/下密炼机明细列宽偏好 localStorage 键(两表共用同步) */ +export const MIXING_STEP_COLUMN_WIDTH_CACHE_KEY = 'mes_xsl_mixing_spec_step_column_widths_v1'; + +/** 读取已保存的混合步骤明细列宽 */ +export function loadMixingStepColumnWidths(): Record { + const saved = mixingMaterialColumnStorage.get(MIXING_STEP_COLUMN_WIDTH_CACHE_KEY); + const validKeys = new Set(stepColumns.map((col) => String(col.key))); + if (!saved || typeof saved !== 'object') { + return {}; + } + const result: Record = {}; + Object.entries(saved as Record).forEach(([key, value]) => { + if (validKeys.has(key) && typeof value === 'number' && value > 0) { + result[key] = value; + } + }); + return result; +} + +/** 保存混合步骤明细列宽 */ +export function saveMixingStepColumnWidths(widthMap: Record) { + const validKeys = new Set(stepColumns.map((col) => String(col.key))); + const next: Record = {}; + Object.entries(widthMap || {}).forEach(([key, value]) => { + if (validKeys.has(key) && typeof value === 'number' && value > 0) { + next[key] = value; + } + }); + if (Object.keys(next).length) { + mixingMaterialColumnStorage.set(MIXING_STEP_COLUMN_WIDTH_CACHE_KEY, next); + return; + } + mixingMaterialColumnStorage.remove(MIXING_STEP_COLUMN_WIDTH_CACHE_KEY); +} + +/** 应用已保存混合步骤列宽(minWidth 保持最小值,允许拖拽缩小) */ +export function applyMixingStepColumnWidths(columns: JVxeColumn[], widthMap: Record): JVxeColumn[] { + return columns.map((col) => { + const savedWidth = widthMap[String(col.key)]; + const nextCol = { + ...col, + minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, + }; + if (savedWidth) { + nextCol.width = savedWidth; + } + return nextCol; + }); +} + +/** 计算混合步骤/下密炼机明细表总宽度 */ +export function calcMixingStepTableWidth(columns: JVxeColumn[] = stepColumns, widthMap: Record = {}) { + const dataWidth = columns.reduce((sum, col) => { + const key = String(col.key); + const width = widthMap[key] ?? Number(col.width) ?? Number(col.minWidth) ?? 80; + return sum + width; + }, 0); + return MIXING_MATERIAL_ROW_NUMBER_WIDTH + dataWidth + 1; +} +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A20】明细表默认列宽对齐参考图----------- + +export const downStepColumns: JVxeColumn[] = [...stepColumns]; + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A19】TCU温度条件表列宽可调且表头换行----------- +/** TCU 温度条件明细列宽偏好 localStorage 键 */ +export const MIXING_TCU_COLUMN_WIDTH_CACHE_KEY = 'mes_xsl_mixing_spec_tcu_column_widths_v2'; + +/** TCU 温度条件明细列可缩小到的最小宽度 */ +export const MIXING_TCU_MIN_COLUMN_WIDTH = 48; + +export const tcuColumns: JVxeColumn[] = [ + { title: '区分', key: 'sectionType', type: JVxeTypes.select, dictCode: 'xslmes_mixing_tcu_section', width: 96, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '前转子温度', key: 'frontRotorTemp', type: JVxeTypes.inputNumber, width: 76, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '后转子温度', key: 'rearRotorTemp', type: JVxeTypes.inputNumber, width: 76, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '前混炼室温度', key: 'frontChamberTemp', type: JVxeTypes.inputNumber, width: 76, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '后混炼室温度', key: 'rearChamberTemp', type: JVxeTypes.inputNumber, width: 76, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '上下顶栓温度', key: 'topPlugTemp', type: JVxeTypes.inputNumber, width: 76, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, + { title: '药品称量位置', key: 'drugWeighPos', type: JVxeTypes.select, dictCode: 'xslmes_mixing_drug_weigh_pos', width: 76, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, +]; + +/** 读取已保存的 TCU 温度条件明细列宽 */ +export function loadMixingTcuColumnWidths(): Record { + const saved = mixingMaterialColumnStorage.get(MIXING_TCU_COLUMN_WIDTH_CACHE_KEY); + const validKeys = new Set(tcuColumns.map((col) => String(col.key))); + if (!saved || typeof saved !== 'object') { + return {}; + } + const result: Record = {}; + Object.entries(saved as Record).forEach(([key, value]) => { + if (validKeys.has(key) && typeof value === 'number' && value > 0) { + result[key] = value; + } + }); + return result; +} + +/** 保存 TCU 温度条件明细列宽 */ +export function saveMixingTcuColumnWidths(widthMap: Record) { + const validKeys = new Set(tcuColumns.map((col) => String(col.key))); + const next: Record = {}; + Object.entries(widthMap || {}).forEach(([key, value]) => { + if (validKeys.has(key) && typeof value === 'number' && value > 0) { + next[key] = value; + } + }); + if (Object.keys(next).length) { + mixingMaterialColumnStorage.set(MIXING_TCU_COLUMN_WIDTH_CACHE_KEY, next); + return; + } + mixingMaterialColumnStorage.remove(MIXING_TCU_COLUMN_WIDTH_CACHE_KEY); +} + +/** 应用已保存 TCU 列宽(minWidth 保持最小值,允许拖拽缩小) */ +export function applyMixingTcuColumnWidths(columns: JVxeColumn[], widthMap: Record): JVxeColumn[] { + return columns.map((col) => { + const savedWidth = widthMap[String(col.key)]; + const nextCol = { + ...col, + minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, + }; + if (savedWidth) { + nextCol.width = savedWidth; + } + return nextCol; + }); +} + +/** 计算 TCU 温度条件明细表总宽度 */ +export function calcMixingTcuTableWidth(columns: JVxeColumn[] = tcuColumns, widthMap: Record = {}) { + const dataWidth = columns.reduce((sum, col) => { + const key = String(col.key); + const width = widthMap[key] ?? Number(col.width) ?? Number(col.minWidth) ?? 80; + return sum + width; + }, 0); + return MIXING_MATERIAL_ROW_NUMBER_WIDTH + dataWidth + 1; +} +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A19】TCU温度条件表列宽可调且表头换行----------- + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A26】TCU紧凑两行且胶料表向下扩展----------- +/** TCU 温度条件固定行数(上密炼机/下密炼机) */ +export const DEFAULT_MIXING_TCU_ROW_COUNT = 2; + +/** TCU 表头高度(列标题换行) */ +export const MIXING_TCU_HEADER_HEIGHT = 48; + +/** 计算 TCU 温度条件表格高度(仅展示固定两行) */ +export function calcMixingTcuTableHeight(rowCount = DEFAULT_MIXING_TCU_ROW_COUNT) { + const rows = Math.max(1, rowCount); + return MIXING_TCU_HEADER_HEIGHT + rows * MIXING_VXE_MINI_ROW_HEIGHT + 2; +} +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A26】TCU紧凑两行且胶料表向下扩展----------- + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A22】明细表默认空行数----------- +/** 橡胶及配合剂明细默认行数 */ +export const DEFAULT_MIXING_MATERIAL_ROW_COUNT = 20; + +/** 混合步骤明细默认行数 */ +export const DEFAULT_MIXING_STEP_ROW_COUNT = 30; + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A30】胶料/混合步骤列表默认展示高度----------- +/** 橡胶及配合剂明细列表默认展示行数(可视高度) */ +export const MIXING_MATERIAL_VISIBLE_ROW_COUNT = 17; + +/** 混合步骤明细列表默认展示行数(可视高度) */ +export const MIXING_STEP_VISIBLE_ROW_COUNT = 15; +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A30】胶料/混合步骤列表默认展示高度----------- + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A27】下密炼机混炼条件默认行数改为4----------- +/** 下密炼机混炼条件明细默认行数 */ +export const DEFAULT_MIXING_DOWN_STEP_ROW_COUNT = 4; +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A27】下密炼机混炼条件默认行数改为4----------- + +/** vxe mini 表头高度 */ +export const MIXING_VXE_MINI_HEADER_HEIGHT = 36; + +/** vxe mini 行高 */ +export const MIXING_VXE_MINI_ROW_HEIGHT = 32; + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A29】胶料/混合步骤表格高度按行数完整展示----------- +/** 计算橡胶及配合剂明细表格展示高度 */ +export function calcMixingMaterialTableHeight(rowCount = MIXING_MATERIAL_VISIBLE_ROW_COUNT) { + const rows = Math.max(1, rowCount); + return MIXING_VXE_MINI_HEADER_HEIGHT + rows * MIXING_VXE_MINI_ROW_HEIGHT + 4; +} + +/** 计算混合步骤明细表格展示高度 */ +export function calcMixingStepTableHeight(rowCount = MIXING_STEP_VISIBLE_ROW_COUNT) { + const rows = Math.max(1, rowCount); + return MIXING_VXE_MINI_HEADER_HEIGHT + rows * MIXING_VXE_MINI_ROW_HEIGHT + 4; +} + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A31】下密炼机4行表格高度微调----------- +/** 计算下密炼机混炼条件表格高度(默认完整展示4行) */ +export function calcMixingDownStepTableHeight(rowCount = DEFAULT_MIXING_DOWN_STEP_ROW_COUNT) { + const rows = Math.max(1, rowCount); + // 额外留白补偿边框与 vxe 内边距,避免第4行底部被裁切 + return MIXING_VXE_MINI_HEADER_HEIGHT + rows * MIXING_VXE_MINI_ROW_HEIGHT + 12; +} +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A31】下密炼机4行表格高度微调----------- +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A29】胶料/混合步骤表格高度按行数完整展示----------- + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A32】四明细表行高/展示行数设置持久化----------- +/** 混炼示方明细表标识 */ +export type MixingDetailTableKey = 'material' | 'tcu' | 'step' | 'downStep'; + +/** 明细表行高与展示行数偏好 */ +export interface MixingTableHeightPreference { + rowHeight: number; + visibleRowCount: number; +} + +/** 明细表行高设置元数据 */ +export interface MixingTableHeightSettingMeta { + key: MixingDetailTableKey; + label: string; + defaultRowHeight: number; + defaultVisibleRowCount: number; + minVisibleRowCount: number; + maxVisibleRowCount: number; + headerHeight: number; + extraPadding: number; +} + +/** 明细表行高 localStorage 键 */ +export const MIXING_TABLE_HEIGHT_PREF_CACHE_KEY = 'mes_xsl_mixing_spec_table_height_prefs_v1'; + +/** 行高可调范围(px) */ +export const MIXING_TABLE_ROW_HEIGHT_MIN = 24; +export const MIXING_TABLE_ROW_HEIGHT_MAX = 56; + +export const MIXING_TABLE_HEIGHT_SETTING_META: Record = { + material: { + key: 'material', + label: '橡胶及配合剂', + defaultRowHeight: MIXING_VXE_MINI_ROW_HEIGHT, + defaultVisibleRowCount: MIXING_MATERIAL_VISIBLE_ROW_COUNT, + minVisibleRowCount: 5, + maxVisibleRowCount: 30, + headerHeight: MIXING_VXE_MINI_HEADER_HEIGHT, + extraPadding: 4, + }, + tcu: { + key: 'tcu', + label: 'TCU温度条件', + defaultRowHeight: MIXING_VXE_MINI_ROW_HEIGHT, + defaultVisibleRowCount: DEFAULT_MIXING_TCU_ROW_COUNT, + minVisibleRowCount: 2, + maxVisibleRowCount: 6, + headerHeight: MIXING_TCU_HEADER_HEIGHT, + extraPadding: 2, + }, + step: { + key: 'step', + label: '混合步骤', + defaultRowHeight: MIXING_VXE_MINI_ROW_HEIGHT, + defaultVisibleRowCount: MIXING_STEP_VISIBLE_ROW_COUNT, + minVisibleRowCount: 5, + maxVisibleRowCount: 40, + headerHeight: MIXING_VXE_MINI_HEADER_HEIGHT, + extraPadding: 4, + }, + downStep: { + key: 'downStep', + label: '下密炼机混炼条件', + defaultRowHeight: MIXING_VXE_MINI_ROW_HEIGHT, + defaultVisibleRowCount: DEFAULT_MIXING_DOWN_STEP_ROW_COUNT, + minVisibleRowCount: 2, + maxVisibleRowCount: 12, + headerHeight: MIXING_VXE_MINI_HEADER_HEIGHT, + extraPadding: 12, + }, +}; + +function clampMixingTableNumber(value: unknown, min: number, max: number, fallback: number) { + const num = Number(value); + if (Number.isNaN(num)) { + return fallback; + } + return Math.min(max, Math.max(min, Math.round(num))); +} + +/** 获取明细表默认行高偏好 */ +export function getMixingTableHeightDefault(tableKey: MixingDetailTableKey): MixingTableHeightPreference { + const meta = MIXING_TABLE_HEIGHT_SETTING_META[tableKey]; + return { + rowHeight: meta.defaultRowHeight, + visibleRowCount: meta.defaultVisibleRowCount, + }; +} + +/** 规范化明细表行高偏好 */ +export function normalizeMixingTableHeightPreference( + tableKey: MixingDetailTableKey, + preference?: Partial | null, +): MixingTableHeightPreference { + const meta = MIXING_TABLE_HEIGHT_SETTING_META[tableKey]; + const defaults = getMixingTableHeightDefault(tableKey); + return { + rowHeight: clampMixingTableNumber( + preference?.rowHeight, + MIXING_TABLE_ROW_HEIGHT_MIN, + MIXING_TABLE_ROW_HEIGHT_MAX, + defaults.rowHeight, + ), + visibleRowCount: clampMixingTableNumber( + preference?.visibleRowCount, + meta.minVisibleRowCount, + meta.maxVisibleRowCount, + defaults.visibleRowCount, + ), + }; +} + +/** 读取明细表行高偏好 */ +export function loadMixingTableHeightPreference(tableKey: MixingDetailTableKey): MixingTableHeightPreference { + const saved = mixingMaterialColumnStorage.get(MIXING_TABLE_HEIGHT_PREF_CACHE_KEY); + const tableSaved = + saved && typeof saved === 'object' ? (saved as Record>)[tableKey] : null; + return normalizeMixingTableHeightPreference(tableKey, tableSaved); +} + +/** 保存明细表行高偏好 */ +export function saveMixingTableHeightPreference(tableKey: MixingDetailTableKey, preference: MixingTableHeightPreference) { + const saved = mixingMaterialColumnStorage.get(MIXING_TABLE_HEIGHT_PREF_CACHE_KEY); + const next = + saved && typeof saved === 'object' + ? { ...(saved as Record) } + : ({} as Record); + next[tableKey] = normalizeMixingTableHeightPreference(tableKey, preference); + mixingMaterialColumnStorage.set(MIXING_TABLE_HEIGHT_PREF_CACHE_KEY, next); +} + +/** 计算明细表展示区域高度 */ +export function calcMixingDetailTableViewportHeight( + tableKey: MixingDetailTableKey, + preference?: Partial, +) { + const meta = MIXING_TABLE_HEIGHT_SETTING_META[tableKey]; + const normalized = normalizeMixingTableHeightPreference(tableKey, preference); + return meta.headerHeight + normalized.visibleRowCount * normalized.rowHeight + meta.extraPadding; +} + +/** 构建 JVxeTable rowConfig */ +export function buildMixingTableRowConfig(preference: MixingTableHeightPreference) { + return { + isHover: true, + height: preference.rowHeight, + }; +} +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A32】四明细表行高/展示行数设置持久化----------- + +function createEmptyMixingRows(count: number): Recordable[] { + return Array.from({ length: count }, () => ({ id: buildUUID() })); +} + +/** 创建橡胶及配合剂默认空行 */ +export function createEmptyMaterialRows(count = DEFAULT_MIXING_MATERIAL_ROW_COUNT): Recordable[] { + return createEmptyMixingRows(count); +} + +/** 创建混合步骤默认空行 */ +export function createEmptyStepRows(count = DEFAULT_MIXING_STEP_ROW_COUNT): Recordable[] { + return createEmptyMixingRows(count); +} + +/** 创建下密炼机混炼条件默认空行 */ +export function createEmptyDownStepRows(count = DEFAULT_MIXING_DOWN_STEP_ROW_COUNT): Recordable[] { + return createEmptyMixingRows(count); +} + +/** 确保明细行具备唯一 id(JVxeTable 依赖 rowKey=id) */ +export function normalizeMixingDetailRows(rows: Recordable[] = []): Recordable[] { + return (rows || []).map((row) => ({ ...row, id: row?.id || buildUUID() })); +} +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A22】明细表默认空行数----------- diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpecList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpecList.vue new file mode 100644 index 0000000..a08595c --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpecList.vue @@ -0,0 +1,115 @@ + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialColumnSetting.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialColumnSetting.vue new file mode 100644 index 0000000..e183f91 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialColumnSetting.vue @@ -0,0 +1,166 @@ + + + + + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue new file mode 100644 index 0000000..4e41b05 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue @@ -0,0 +1,1174 @@ + + + + + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingTableRowHeightSetting.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingTableRowHeightSetting.vue new file mode 100644 index 0000000..5941373 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingTableRowHeightSetting.vue @@ -0,0 +1,169 @@ + + + + + + + From c85657d1995fe66969cc660634e47b928a6c53e7 Mon Sep 17 00:00:00 2001 From: geht <2947093423@qq.com> Date: Fri, 22 May 2026 19:43:41 +0800 Subject: [PATCH 03/10] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B7=B7=E7=82=BC?= =?UTF-8?q?=E7=A4=BA=E6=96=B9=E7=94=9F=E6=88=90=E9=A2=84=E8=A7=88=E4=B8=8E?= =?UTF-8?q?=E6=89=B9=E9=87=8F=E5=88=9B=E5=BB=BA=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=9B=B8=E5=85=B3=E5=AD=97=E6=AE=B5=E5=8F=8A?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E4=BA=A4=E4=BA=92=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E7=B3=BB=E7=BB=9F=E7=A8=B3=E5=AE=9A=E6=80=A7?= =?UTF-8?q?=E5=92=8C=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jeecg-module-xslmes/doc/代码修改日志 | 57 ++ .../MesXslFormulaSpecController.java | 28 + .../xslmes/entity/MesXslMixingSpec.java | 4 +- .../service/IMesXslFormulaSpecService.java | 16 + .../impl/MesXslFormulaSpecServiceImpl.java | 503 ++++++++++++++++++ .../MesXslFormulaMixingGenerateMachineVO.java | 16 + ...XslFormulaMixingGeneratePreviewItemVO.java | 25 + .../MesXslFormulaMixingGeneratePreviewVO.java | 23 + .../MesXslFormulaMixingGenerateRequestVO.java | 17 + .../vo/MesXslFormulaMixingGenerateRowVO.java | 26 + .../jeecg-system-biz/docs/代码修改日志 | 8 + .../modules/system/entity/SysCategory.java | 3 + .../service/impl/SysCategoryServiceImpl.java | 32 ++ ..._mes_xsl_mixing_spec_stage_count_total.sql | 3 + ...l_mixing_spec_stage_count_revert_total.sql | 4 + .../V3.9.2_99__sys_category_is_rubber.sql | 20 + .../MesMixerMaterialSysCategoryModal.vue | 44 +- .../system/category/category.constants.ts | 22 + .../views/system/category/category.data.ts | 10 + .../category/components/CategoryModal.vue | 31 ++ .../MesXslEquipmentLedgerMultiSelectModal.vue | 76 +++ .../MesXslFormulaSpec.api.ts | 8 + .../MesXslFormulaSpecList.vue | 26 + .../MesXslFormulaGenerateMixingModal.vue | 193 +++++++ .../components/MesXslFormulaSpecModal.vue | 27 + .../MesXslMixerActionSelectModal.vue | 91 ++++ .../MesXslMixerConditionSelectModal.vue | 91 ++++ .../mesXslMixingSpec/MesXslMixingSpec.data.ts | 66 ++- .../components/MesXslMixingSpecModal.vue | 268 ++++++++-- .../components/MesXslMixingStepSelectCell.vue | 109 ++++ 30 files changed, 1786 insertions(+), 61 deletions(-) create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateMachineVO.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGeneratePreviewItemVO.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGeneratePreviewVO.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateRequestVO.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateRowVO.java create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_100__mes_xsl_mixing_spec_stage_count_total.sql create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_101__mes_xsl_mixing_spec_stage_count_revert_total.sql create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_99__sys_category_is_rubber.sql create mode 100644 jeecgboot-vue3/src/views/system/category/category.constants.ts create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaGenerateMixingModal.vue create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixerAction/components/MesXslMixerActionSelectModal.vue create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixerCondition/components/MesXslMixerConditionSelectModal.vue create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingStepSelectCell.vue diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 index 04a7f2a..f980ca7 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 @@ -132,3 +132,60 @@ jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpecList.vue jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A33】新增混炼示方主表/明细字段交互优化 --- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixerAction/components/MesXslMixerActionSelectModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixerCondition/components/MesXslMixerConditionSelectModal.vue + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A34】混炼示方动作/组合改为下拉选择 --- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A35】混炼示方动作/组合列常显下拉倒三角 --- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingStepSelectCell.vue + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】F段明细加入最后一段B炼好胶(如三段用B2)+Q列配合剂 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】B2/Bn明细改为上一段胶料一条(B{n-1}+胶料名)+本段列配合剂 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】修复B2与B1相同:按列增量拼接并支持列2+非Q配合剂 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateRowVO.java +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaGenerateMixingModal.vue + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】生成混炼示方B段改为Bn=B(n-1)+第n列有值配合剂增量拼接 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】生成混炼示方明细种类按分类字典is_rubber显示胶料或小类名 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】生成混炼示方编号原样追加胶料代号中胶料名称后的后缀 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】生成混炼示方明细按STEP过滤:B段仅A物料、F段仅Q物料 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】配合示方生成混炼示方(预览段×机台批量创建) --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerate*.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslFormulaSpecController.java +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpecList.vue +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaGenerateMixingModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A36】混炼示方动作/组合下拉列表被表格裁切修复 --- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingStepSelectCell.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue + +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A37】未选机台点击动作/组合提示请先选择机台 --- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingStepSelectCell.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslFormulaSpecController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslFormulaSpecController.java index 0ad744a..7c752dc 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslFormulaSpecController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslFormulaSpecController.java @@ -25,6 +25,8 @@ import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec; import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine; import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecService; import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecSettingService; +import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGeneratePreviewVO; +import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateRequestVO; import org.jeecg.modules.xslmes.vo.MesXslFormulaRubberContentSettingVO; import org.jeecg.modules.xslmes.vo.MesXslFormulaSpecPage; import org.springframework.beans.BeanUtils; @@ -173,6 +175,32 @@ public class MesXslFormulaSpecController extends JeecgController buildMixingGeneratePreview( + @RequestParam(name = "formulaSpecId", required = true) String formulaSpecId) { + try { + return Result.OK(mesXslFormulaSpecService.buildMixingGeneratePreview(formulaSpecId)); + } catch (IllegalArgumentException ex) { + return Result.error(ex.getMessage()); + } + } + + @AutoLog(value = "MES配合示方-生成混炼示方") + @Operation(summary = "MES配合示方-生成混炼示方") + @RequiresPermissions("xslmes:mes_xsl_mixing_spec:add") + @PostMapping(value = "/generateMixingSpec") + public Result> generateMixingSpec(@RequestBody MesXslFormulaMixingGenerateRequestVO request) { + try { + int count = mesXslFormulaSpecService.generateMixingSpecFromFormula(request); + return Result.OK("成功生成 " + count + " 条混炼示方", Map.of("count", count)); + } catch (IllegalArgumentException ex) { + return Result.error(ex.getMessage()); + } + } + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方----------- + @RequiresPermissions("xslmes:mes_xsl_formula_spec:exportXls") @RequestMapping(value = "/exportXls") public ModelAndView exportXls(HttpServletRequest request, MesXslFormulaSpec model) { diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpec.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpec.java index ea6c7e6..25c9d2a 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpec.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpec.java @@ -75,8 +75,8 @@ public class MesXslMixingSpec implements Serializable { @Schema(description = "适用工厂") private String applyFactory; - @Schema(description = "段数") - private Integer stageCount; + @Schema(description = "段数(当前/总,如2/3)") + private String stageCount; @Schema(description = "纯混炼时间(秒)") private Integer pureMixSec; diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java index 8bab67c..9cbbdc0 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java @@ -7,6 +7,8 @@ import java.util.List; import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec; import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine; import org.jeecg.modules.xslmes.entity.MesXslMixerPsCompile; +import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGeneratePreviewVO; +import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateRequestVO; public interface IMesXslFormulaSpecService extends IService { @@ -36,4 +38,18 @@ public interface IMesXslFormulaSpecService extends IService { */ void syncFromMixerPsWorkflow(MesXslMixerPsCompile ps, String mixerPsTargetStatus); //update-end---author:cursor ---date:20260522 for:【配合示方】密炼PS审批联动同步状态与审批人----------- + + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方预览与批量创建----------- + /** + * 根据配合示方混合段数构建生成混炼示方预览行(示方编号 + 段信息) + */ + MesXslFormulaMixingGeneratePreviewVO buildMixingGeneratePreview(String formulaSpecId); + + /** + * 按预览行×机台批量生成混炼示方(含橡胶及配合剂明细) + * + * @return 成功生成的混炼示方条数 + */ + int generateMixingSpecFromFormula(MesXslFormulaMixingGenerateRequestVO request); + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方预览与批量创建----------- } 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 dcdeaf2..883b7f0 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 @@ -7,6 +7,7 @@ import jakarta.annotation.Resource; import java.io.Serializable; import java.math.BigDecimal; import java.math.RoundingMode; +import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; @@ -14,6 +15,8 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.time.LocalDate; +import java.time.ZoneId; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; @@ -22,13 +25,23 @@ import org.jeecg.modules.mes.material.entity.MesMixerMaterial; import org.jeecg.modules.mes.material.service.IMesMaterialService; import org.jeecg.modules.mes.material.service.IMesMixerMaterialService; import org.jeecg.common.util.oConvertUtils; +import org.jeecg.modules.system.entity.SysCategory; +import org.jeecg.modules.system.service.ISysCategoryService; import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec; import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine; import org.jeecg.modules.xslmes.entity.MesXslMixerPsCompile; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpec; +import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial; import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecLineMapper; import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecMapper; import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecService; import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecSettingService; +import org.jeecg.modules.xslmes.service.IMesXslMixingSpecService; +import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateMachineVO; +import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGeneratePreviewItemVO; +import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGeneratePreviewVO; +import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateRequestVO; +import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateRowVO; import org.jeecg.modules.system.entity.SysUser; import org.jeecg.modules.system.service.ISysUserService; import org.springframework.stereotype.Service; @@ -57,6 +70,12 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl lineList) { @@ -434,4 +453,488 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl items = new ArrayList<>(); + int aIndex = 0; + for (int i = 1; i <= stageCount; i++) { + boolean isQSegment = hasQ && i == stageCount; + MesXslFormulaMixingGeneratePreviewItemVO item = new MesXslFormulaMixingGeneratePreviewItemVO(); + item.setRowKey(i); + item.setStageIndex(i); + if (isQSegment) { + item.setStepType("Q"); + item.setSpecCode(appendFormulaCodeSuffix("F" + rubberName, formulaCodeSuffix)); + item.setASegmentIndex(null); + } else { + aIndex++; + item.setStepType("A"); + item.setASegmentIndex(aIndex); + item.setSpecCode(appendFormulaCodeSuffix("B" + aIndex + rubberName, formulaCodeSuffix)); + } + items.add(item); + } + MesXslFormulaMixingGeneratePreviewVO preview = new MesXslFormulaMixingGeneratePreviewVO(); + preview.setFormulaSpecId(formulaSpecId); + preview.setRubberName(rubberName); + preview.setMixingStages(stageCount); + preview.setItems(items); + return preview; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int generateMixingSpecFromFormula(MesXslFormulaMixingGenerateRequestVO request) { + if (request == null || oConvertUtils.isEmpty(request.getFormulaSpecId())) { + throw new IllegalArgumentException("配合示方ID不能为空"); + } + if (CollectionUtils.isEmpty(request.getRows())) { + throw new IllegalArgumentException("请至少配置一行示方与机台"); + } + MesXslFormulaSpec formula = getByIdWithLines(request.getFormulaSpecId()); + if (formula == null) { + throw new IllegalArgumentException("未找到配合示方数据"); + } + List lines = formula.getLineList(); + if (CollectionUtils.isEmpty(lines)) { + throw new IllegalArgumentException("配合示方明细为空,无法生成混炼示方"); + } + Map mixerCache = new HashMap<>(); + Map categoryNameCache = new HashMap<>(); + Map categoryRubberCache = new HashMap<>(); + int created = 0; + int totalStages = normalizeMixingStages(formula.getMixingStages()); + Date today = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()); + for (MesXslFormulaMixingGenerateRowVO row : request.getRows()) { + if (row == null || oConvertUtils.isEmpty(row.getSpecCode()) || row.getStageIndex() == null) { + continue; + } + if (CollectionUtils.isEmpty(row.getMachines())) { + throw new IllegalArgumentException("示方「" + row.getSpecCode() + "」请至少选择一个机台"); + } + String materialStep = resolveMixingMaterialStep(row); + int mixingColumn = resolveMixingColumn(row, formula); + List materials = buildMixingMaterials( + formula, lines, mixingColumn, materialStep, mixerCache, categoryNameCache, categoryRubberCache); + for (MesXslFormulaMixingGenerateMachineVO machine : row.getMachines()) { + if (machine == null || oConvertUtils.isEmpty(machine.getMachineId())) { + continue; + } + MesXslMixingSpec mixing = new MesXslMixingSpec(); + mixing.setSpecName(row.getSpecCode()); + mixing.setPurpose(formula.getPurpose()); + mixing.setIssueNumber(formula.getIssueNumber()); + mixing.setMachineId(machine.getMachineId()); + mixing.setMachineName(machine.getMachineName()); + mixing.setMakeDate(today); + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A40】生成时写入段数当前/总如2/3----------- + if (row.getStageIndex() != null && totalStages > 0) { + mixing.setStageCount(row.getStageIndex() + "/" + totalStages); + } else if (row.getStageIndex() != null) { + mixing.setStageCount(String.valueOf(row.getStageIndex())); + } + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A40】生成时写入段数当前/总如2/3----------- + if ("Q".equalsIgnoreCase(row.getStepType())) { + mixing.setFinalRubberSg(formula.getQRubberSg()); + } else { + mixing.setMotherRubberSg(formula.getARubberSg()); + } + mesXslMixingSpecService.saveMain(mixing, materials, null, null, null); + created++; + } + } + if (created <= 0) { + throw new IllegalArgumentException("未生成任何混炼示方,请检查机台配置"); + } + return created; + } + + private int normalizeMixingStages(Integer mixingStages) { + if (mixingStages == null || mixingStages <= 0) { + return 0; + } + return Math.min(mixingStages, 7); + } + + private String resolveRubberName(MesXslFormulaSpec main) { + if (StringUtils.isNotBlank(main.getBasicFormula())) { + return main.getBasicFormula().trim(); + } + if (StringUtils.isNotBlank(main.getRubberMaterialId())) { + MesMaterial rubber = mesMaterialService.getById(main.getRubberMaterialId()); + if (rubber != null && StringUtils.isNotBlank(rubber.getMaterialName())) { + return rubber.getMaterialName().trim(); + } + } + return ""; + } + + /** + * 配合示方胶料代号/示方编号中,胶料名称之后的后缀原样截取(如 SA01、SB01 等,不做固定拼接)。 + */ + private String resolveFormulaCodeSuffix(MesXslFormulaSpec main) { + if (main == null) { + return ""; + } + String code = StringUtils.isNotBlank(main.getRubberCode()) ? main.getRubberCode().trim() : ""; + if (StringUtils.isBlank(code) && StringUtils.isNotBlank(main.getSpecCode())) { + code = main.getSpecCode().trim(); + } + if (StringUtils.isBlank(code)) { + return ""; + } + String rubberName = resolveRubberName(main); + if (StringUtils.isBlank(rubberName)) { + return ""; + } + int nameIndex = code.indexOf(rubberName); + if (nameIndex >= 0 && nameIndex + rubberName.length() < code.length()) { + return code.substring(nameIndex + rubberName.length()); + } + String dNamePrefix = "D" + rubberName; + if (code.startsWith(dNamePrefix) && code.length() > dNamePrefix.length()) { + return code.substring(dNamePrefix.length()); + } + return ""; + } + + private String appendFormulaCodeSuffix(String baseSpecCode, String formulaCodeSuffix) { + if (StringUtils.isBlank(baseSpecCode)) { + return baseSpecCode; + } + if (StringUtils.isBlank(formulaCodeSuffix)) { + return baseSpecCode; + } + return baseSpecCode + formulaCodeSuffix; + } + + private boolean hasStepQ(List lines) { + if (CollectionUtils.isEmpty(lines)) { + return false; + } + for (MesXslFormulaSpecLine line : lines) { + if (line != null && "Q".equalsIgnoreCase(line.getStep())) { + return true; + } + } + return false; + } + + /** 解析 B/F 段对应的配合示方混合段列号 */ + private int resolveMixingColumn(MesXslFormulaMixingGenerateRowVO row, MesXslFormulaSpec formula) { + if ("Q".equalsIgnoreCase(resolveMixingMaterialStep(row))) { + Integer stages = formula != null ? formula.getMixingStages() : null; + if (stages != null && stages > 0) { + return Math.min(stages, 7); + } + } + if (row != null && row.getASegmentIndex() != null && row.getASegmentIndex() > 0) { + return Math.min(row.getASegmentIndex(), 7); + } + if (row != null && row.getStageIndex() != null && row.getStageIndex() > 0) { + return Math.min(row.getStageIndex(), 7); + } + String specCode = row != null ? row.getSpecCode() : null; + if (StringUtils.isNotBlank(specCode)) { + Matcher matcher = Pattern.compile("(?i)B(\\d+)").matcher(specCode.trim()); + if (matcher.find()) { + return Math.min(Integer.parseInt(matcher.group(1)), 7); + } + } + return 1; + } + + /** + * B1=第一段配合剂(列1 STEP=A);Bn(n>1)=上一段胶料示方一条(B{n-1}+胶料名)+本段列n配合剂。 + * F 段=最后一段B炼好胶一条(如三段时B2+胶料名)+本列 STEP=Q 配合剂。 + */ + private String resolveMixingMaterialStep(MesXslFormulaMixingGenerateRowVO row) { + if (row != null && StringUtils.isNotBlank(row.getStepType())) { + return row.getStepType().trim().toUpperCase(); + } + String specCode = row != null ? row.getSpecCode() : null; + if (StringUtils.isNotBlank(specCode) && specCode.trim().toUpperCase().startsWith("F")) { + return "Q"; + } + return "A"; + } + + private List buildMixingMaterials( + MesXslFormulaSpec formula, + List lines, + int stageIndex, + String materialStep, + Map mixerCache, + Map categoryNameCache, + Map categoryRubberCache) { + String stepFilter = StringUtils.isNotBlank(materialStep) ? materialStep.trim().toUpperCase() : "A"; + List materials = new ArrayList<>(); + int sort = 0; + if ("Q".equals(stepFilter)) { + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】F段加入最后一段B炼好胶料一条再加Q配合剂----------- + String rubberName = resolveRubberName(formula); + String codeSuffix = resolveFormulaCodeSuffix(formula); + int lastBSegment = resolveLastBSegmentIndex(formula, lines); + if (lastBSegment > 0) { + String motherSpecCode = appendFormulaCodeSuffix("B" + lastBSegment + rubberName, codeSuffix); + BigDecimal motherWeight = resolveStageCumulativeTotal(formula, lines, lastBSegment); + materials.add(createMotherRubberMaterial(motherSpecCode, rubberName, motherWeight, materials.size())); + } + appendQStageColumnAgents(lines, stageIndex, materials, mixerCache, categoryNameCache, categoryRubberCache); + reindexMaterialSortNo(materials); + return materials; + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】F段加入最后一段B炼好胶料一条再加Q配合剂----------- + } + int bColumn = Math.max(stageIndex, 1); + String rubberName = resolveRubberName(formula); + String codeSuffix = resolveFormulaCodeSuffix(formula); + if (bColumn <= 1) { + appendBStageColumnAgents(lines, 1, materials, mixerCache, categoryNameCache, categoryRubberCache); + reindexMaterialSortNo(materials); + return materials; + } + // B2/B3…:上一段炼好胶料一条(如 B1+胶料名) + 本段列配合剂 + int prevB = bColumn - 1; + String motherSpecCode = appendFormulaCodeSuffix("B" + prevB + rubberName, codeSuffix); + BigDecimal motherWeight = resolveStageCumulativeTotal(formula, lines, prevB); + materials.add(createMotherRubberMaterial(motherSpecCode, rubberName, motherWeight, materials.size())); + appendBStageColumnAgents(lines, bColumn, materials, mixerCache, categoryNameCache, categoryRubberCache); + reindexMaterialSortNo(materials); + return materials; + } + + /** 含 Q 时最后一段 B 的段号(如混合段3段则最后 B 为 B2) */ + private int resolveLastBSegmentIndex(MesXslFormulaSpec formula, List lines) { + int stageCount = normalizeMixingStages(formula != null ? formula.getMixingStages() : null); + if (stageCount <= 0 || !hasStepQ(lines)) { + return 0; + } + return stageCount > 1 ? stageCount - 1 : 0; + } + + /** F 段本列:STEP=Q 且该列有数值的配合剂 */ + private void appendQStageColumnAgents( + List lines, + int column, + List materials, + Map mixerCache, + Map categoryNameCache, + Map categoryRubberCache) { + for (MesXslFormulaSpecLine line : lines) { + if (!isLineStep(line, "Q")) { + continue; + } + BigDecimal unitWeight = readStageValue(line, column); + if (!hasStageNumericValue(unitWeight)) { + continue; + } + materials.add( + toMixingMaterial(line, unitWeight, materials.size(), mixerCache, categoryNameCache, categoryRubberCache)); + } + } + + /** 本段列:STEP=A 且该列有数值的配合剂 */ + private void appendBStageColumnAgents( + List lines, + int column, + List materials, + Map mixerCache, + Map categoryNameCache, + Map categoryRubberCache) { + for (MesXslFormulaSpecLine line : lines) { + if (!isLineStep(line, "A")) { + continue; + } + BigDecimal unitWeight = resolveBColumnUnitWeight(line, column); + if (!hasStageNumericValue(unitWeight)) { + continue; + } + materials.add( + toMixingMaterial(line, unitWeight, materials.size(), mixerCache, categoryNameCache, categoryRubberCache)); + } + } + + /** 上一段密炼产出胶料(一条):示方编号 B{n-1}+胶料名,种类=胶料 */ + private MesXslMixingSpecMaterial createMotherRubberMaterial( + String motherSpecCode, String rubberName, BigDecimal unitWeight, int sortNo) { + MesXslMixingSpecMaterial material = new MesXslMixingSpecMaterial(); + material.setSortNo(sortNo); + material.setMixerMaterialName(motherSpecCode); + material.setMixerMaterialDesc(StringUtils.isNotBlank(rubberName) ? rubberName : motherSpecCode); + material.setMaterialKind("胶料"); + material.setUnitWeight(unitWeight); + return material; + } + + /** 混合段累计合计:优先主表 stageNTotal,否则按明细该列求和 */ + private BigDecimal resolveStageCumulativeTotal(MesXslFormulaSpec formula, List lines, int column) { + BigDecimal fromMain = readStageTotalFromMain(formula, column); + if (hasStageNumericValue(fromMain)) { + return fromMain; + } + BigDecimal sum = BigDecimal.ZERO; + boolean hasAny = false; + for (MesXslFormulaSpecLine line : lines) { + if (line == null) { + continue; + } + BigDecimal w = readStageValue(line, column); + if (!hasStageNumericValue(w)) { + continue; + } + sum = sum.add(w); + hasAny = true; + } + return hasAny ? sum : null; + } + + private BigDecimal readStageTotalFromMain(MesXslFormulaSpec formula, int column) { + if (formula == null || column < 1 || column > 7) { + return null; + } + return switch (column) { + case 1 -> formula.getStage1Total(); + case 2 -> formula.getStage2Total(); + case 3 -> formula.getStage3Total(); + case 4 -> formula.getStage4Total(); + case 5 -> formula.getStage5Total(); + case 6 -> formula.getStage6Total(); + case 7 -> formula.getStage7Total(); + default -> null; + }; + } + + /** B 段单重:优先取当前列;第1列 STEP=A 可回退 PHR */ + private BigDecimal resolveBColumnUnitWeight(MesXslFormulaSpecLine line, int column) { + BigDecimal weight = readStageValue(line, column); + if (hasStageNumericValue(weight)) { + return weight; + } + if (column == 1 && isLineStep(line, "A") && line.getPhr() != null) { + return line.getPhr(); + } + return null; + } + + private void reindexMaterialSortNo(List materials) { + for (int i = 0; i < materials.size(); i++) { + materials.get(i).setSortNo(i); + } + } + + private boolean isLineStep(MesXslFormulaSpecLine line, String step) { + if (line == null || StringUtils.isBlank(step)) { + return false; + } + String lineStep = StringUtils.isNotBlank(line.getStep()) ? line.getStep().trim().toUpperCase() : ""; + return step.equalsIgnoreCase(lineStep); + } + + /** 混合段列是否有有效数值(非空且非 0) */ + private boolean hasStageNumericValue(BigDecimal value) { + return value != null && value.compareTo(BigDecimal.ZERO) != 0; + } + + private MesXslMixingSpecMaterial toMixingMaterial( + MesXslFormulaSpecLine line, + BigDecimal unitWeight, + int sortNo, + Map mixerCache, + Map categoryNameCache, + Map categoryRubberCache) { + MesXslMixingSpecMaterial material = new MesXslMixingSpecMaterial(); + material.setSortNo(sortNo); + material.setMixerMaterialName(line.getMixerMaterialName()); + material.setMixerMaterialDesc( + StringUtils.isNotBlank(line.getMaterialDesc()) ? line.getMaterialDesc() : line.getMixerMaterialName()); + material.setUnitWeight(unitWeight); + fillMaterialCategory(material, line.getMixerMaterialId(), mixerCache, categoryNameCache, categoryRubberCache); + return material; + } + + private BigDecimal readStageValue(MesXslFormulaSpecLine line, int stageIndex) { + if (line == null || stageIndex < 1 || stageIndex > 7) { + return null; + } + return switch (stageIndex) { + case 1 -> line.getStage1(); + case 2 -> line.getStage2(); + case 3 -> line.getStage3(); + case 4 -> line.getStage4(); + case 5 -> line.getStage5(); + case 6 -> line.getStage6(); + case 7 -> line.getStage7(); + default -> null; + }; + } + + private void fillMaterialCategory( + MesXslMixingSpecMaterial material, + String mixerMaterialId, + Map mixerCache, + Map categoryNameCache, + Map categoryRubberCache) { + if (oConvertUtils.isEmpty(mixerMaterialId)) { + return; + } + MesMixerMaterial mixer = mixerCache.computeIfAbsent(mixerMaterialId, id -> mesMixerMaterialService.getById(id)); + if (mixer == null) { + return; + } + String majorName = resolveCategoryName(mixer.getMajorCategoryId(), categoryNameCache); + String minorName = resolveCategoryName(mixer.getMinorCategoryId(), categoryNameCache); + material.setMaterialMajor(majorName); + material.setMaterialMinor(minorName); + material.setMaterialKind(resolveMixingMaterialKind(mixer.getMinorCategoryId(), minorName, categoryRubberCache)); + } + + /** + * 种类:物料小类在分类字典勾选「胶料」则显示「胶料」,否则显示小类分类名称。 + */ + private String resolveMixingMaterialKind( + String minorCategoryId, String minorCategoryName, Map categoryRubberCache) { + if (isCategoryRubber(minorCategoryId, categoryRubberCache)) { + return "胶料"; + } + if (StringUtils.isNotBlank(minorCategoryName)) { + return minorCategoryName; + } + return null; + } + + private boolean isCategoryRubber(String categoryId, Map cache) { + if (oConvertUtils.isEmpty(categoryId)) { + return false; + } + return Boolean.TRUE.equals(cache.computeIfAbsent(categoryId, this::loadCategoryIsRubber)); + } + + private Boolean loadCategoryIsRubber(String categoryId) { + SysCategory category = sysCategoryService.getById(categoryId); + return category != null && "1".equals(category.getIsRubber()); + } + + private String resolveCategoryName(String categoryId, Map cache) { + if (oConvertUtils.isEmpty(categoryId)) { + return null; + } + return cache.computeIfAbsent(categoryId, id -> { + SysCategory category = sysCategoryService.getById(id); + return category != null ? category.getName() : null; + }); + } + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方预览与批量创建----------- } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateMachineVO.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateMachineVO.java new file mode 100644 index 0000000..4ec29c2 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateMachineVO.java @@ -0,0 +1,16 @@ +package org.jeecg.modules.xslmes.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** 生成混炼示方:机台 */ +@Data +@Schema(description = "生成混炼示方机台") +public class MesXslFormulaMixingGenerateMachineVO { + + @Schema(description = "设备台账ID") + private String machineId; + + @Schema(description = "机台名称") + private String machineName; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGeneratePreviewItemVO.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGeneratePreviewItemVO.java new file mode 100644 index 0000000..7c7677c --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGeneratePreviewItemVO.java @@ -0,0 +1,25 @@ +package org.jeecg.modules.xslmes.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** 生成混炼示方:预览行 */ +@Data +@Schema(description = "生成混炼示方预览行") +public class MesXslFormulaMixingGeneratePreviewItemVO { + + @Schema(description = "行键(段序号)") + private Integer rowKey; + + @Schema(description = "示方编号(规格)") + private String specCode; + + @Schema(description = "混合段序号 1-7") + private Integer stageIndex; + + @Schema(description = "段类型:A 或 Q") + private String stepType; + + @Schema(description = "A段序号(仅A段有值)") + private Integer aSegmentIndex; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGeneratePreviewVO.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGeneratePreviewVO.java new file mode 100644 index 0000000..ffbadbc --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGeneratePreviewVO.java @@ -0,0 +1,23 @@ +package org.jeecg.modules.xslmes.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import lombok.Data; + +/** 生成混炼示方:预览结果 */ +@Data +@Schema(description = "生成混炼示方预览") +public class MesXslFormulaMixingGeneratePreviewVO { + + @Schema(description = "配合示方ID") + private String formulaSpecId; + + @Schema(description = "胶料名称") + private String rubberName; + + @Schema(description = "混合段数") + private Integer mixingStages; + + @Schema(description = "预览行") + private List items; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateRequestVO.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateRequestVO.java new file mode 100644 index 0000000..479d0e0 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateRequestVO.java @@ -0,0 +1,17 @@ +package org.jeecg.modules.xslmes.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import lombok.Data; + +/** 生成混炼示方:确认请求 */ +@Data +@Schema(description = "生成混炼示方确认请求") +public class MesXslFormulaMixingGenerateRequestVO { + + @Schema(description = "配合示方ID") + private String formulaSpecId; + + @Schema(description = "确认行") + private List rows; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateRowVO.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateRowVO.java new file mode 100644 index 0000000..858f462 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateRowVO.java @@ -0,0 +1,26 @@ +package org.jeecg.modules.xslmes.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import lombok.Data; + +/** 生成混炼示方:确认行(含机台) */ +@Data +@Schema(description = "生成混炼示方确认行") +public class MesXslFormulaMixingGenerateRowVO { + + @Schema(description = "示方编号(规格)") + private String specCode; + + @Schema(description = "混合段序号 1-7") + private Integer stageIndex; + + @Schema(description = "A段序号(B1/B2…,仅A段有值)") + private Integer aSegmentIndex; + + @Schema(description = "段类型:A 或 Q") + private String stepType; + + @Schema(description = "机台列表") + private List machines; +} diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/docs/代码修改日志 b/jeecg-boot/jeecg-module-system/jeecg-system-biz/docs/代码修改日志 index f6f1358..cd16fb7 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/docs/代码修改日志 +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/docs/代码修改日志 @@ -418,3 +418,11 @@ jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectRecord/MesXslEquipInspectRecor jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectRecord/MesXslEquipInspectRecordList.vue jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectRecord/components/MesXslEquipInspectRecordModal.vue jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectRecord/components/MesXslEquipInspectRecordHandleModal.vue +-- author:cursor---date:20260522--for: 【XSLMES-20260522-A31】分类字典原辅材料子类增加胶料标记字段 --- +jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_99__sys_category_is_rubber.sql +jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysCategory.java +jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java +jeecgboot-vue3/src/views/system/category/category.constants.ts +jeecgboot-vue3/src/views/system/category/category.data.ts +jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue +jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysCategory.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysCategory.java index e19273b..ee2f609 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysCategory.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysCategory.java @@ -49,6 +49,9 @@ public class SysCategory implements Serializable,Comparable{ /**是否有子节点*/ @Excel(name = "是否有子节点(1:有)", width = 15) private java.lang.String hasChild; + /**是否胶料(仅原辅材料子类有效) 1是/0否*/ + @Excel(name = "是否胶料", width = 15) + private java.lang.String isRubber; /**租户ID*/ private java.lang.Integer tenantId; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java index 5410273..869b23c 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java @@ -29,6 +29,9 @@ import java.util.stream.Collectors; @Service public class SysCategoryServiceImpl extends ServiceImpl implements ISysCategoryService { + /** 原辅材料分类编码(其子类可标记为胶料) */ + private static final String MATERIAL_RAW_AUX_CODE = "XSLMES_MATERIAL_RAW_AUX"; + @Override public void addSysCategory(SysCategory sysCategory) { String categoryPid = ISysCategoryService.ROOT_PID_VALUE; @@ -64,6 +67,9 @@ public class SysCategoryServiceImpl extends ServiceImpl queryListByCode(String pcode) throws JeecgBootException{ String pid = ROOT_PID_VALUE; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_100__mes_xsl_mixing_spec_stage_count_total.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_100__mes_xsl_mixing_spec_stage_count_total.sql new file mode 100644 index 0000000..bae3528 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_100__mes_xsl_mixing_spec_stage_count_total.sql @@ -0,0 +1,3 @@ +-- 段数存「当前段/总段数」文本,如 2/3(不新增字段) +ALTER TABLE `mes_xsl_mixing_spec` + MODIFY COLUMN `stage_count` varchar(20) DEFAULT NULL COMMENT '段数(当前/总)'; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_101__mes_xsl_mixing_spec_stage_count_revert_total.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_101__mes_xsl_mixing_spec_stage_count_revert_total.sql new file mode 100644 index 0000000..a85d7fc --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_101__mes_xsl_mixing_spec_stage_count_revert_total.sql @@ -0,0 +1,4 @@ +-- 回退误加的 stage_count_total,并确保 stage_count 为 varchar +ALTER TABLE `mes_xsl_mixing_spec` DROP COLUMN IF EXISTS `stage_count_total`; +ALTER TABLE `mes_xsl_mixing_spec` + MODIFY COLUMN `stage_count` varchar(20) DEFAULT NULL COMMENT '段数(当前/总)'; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_99__sys_category_is_rubber.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_99__sys_category_is_rubber.sql new file mode 100644 index 0000000..dd2daf0 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_99__sys_category_is_rubber.sql @@ -0,0 +1,20 @@ +-- 分类字典:原辅材料子类增加「胶料」标记字段(幂等) +SET NAMES utf8mb4; + +SET @db = DATABASE(); + +SET @sql = IF( + (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'sys_category' AND COLUMN_NAME = 'is_rubber') = 0, + 'ALTER TABLE `sys_category` ADD COLUMN `is_rubber` varchar(1) DEFAULT ''0'' COMMENT ''是否胶料 1是/0否'' AFTER `has_child`', + 'SELECT 1' +); +PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; + +-- 天然胶、合成胶、再生胶默认标记为胶料 +UPDATE `sys_category` +SET `is_rubber` = '1', `update_by` = 'admin', `update_time` = NOW() +WHERE `code` IN ( + 'XSLMES_MATERIAL_RAW_AUX_TRJ', + 'XSLMES_MATERIAL_RAW_AUX_HCJ', + 'XSLMES_MATERIAL_RAW_AUX_ZSJ' +); diff --git a/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue b/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue index fe6a3f2..9750f98 100644 --- a/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue +++ b/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue @@ -10,6 +10,13 @@ import { BasicModal, useModalInner } from '/@/components/Modal'; import { BasicForm, useForm } from '/@/components/Form'; import { defHttp } from '/@/utils/http/axios'; import { loadTreeData } from '/@/views/system/category/category.api'; +import { + MATERIAL_RAW_AUX_CODE, + materialRawAuxCategoryId, + isMaterialRawAuxSubCategory, + toIsRubberFlag, + fromIsRubberFlag, +} from '/@/views/system/category/category.constants'; import { useMessage } from '/@/hooks/web/useMessage'; import type { FormSchema } from '/@/components/Form'; import type { Recordable } from '/@/types/global'; @@ -34,6 +41,15 @@ const schemas: FormSchema[] = [ required: true, componentProps: { maxlength: 50, placeholder: '请输入分类名称' }, }, + { + label: ' ', + field: 'isRubber', + component: 'Checkbox', + defaultValue: false, + renderComponentContent: '胶料', + colProps: { span: 24 }, + ifShow: ({ values }) => isMaterialRawAuxSubCategory(values.pid), + }, ]; const [registerForm, { resetFields, setFieldsValue, validate, updateSchema, scrollToField }] = useForm({ @@ -64,10 +80,30 @@ async function buildPidTree(): Promise { ]; } +async function ensureMaterialRawAuxCategoryId() { + if (materialRawAuxCategoryId.value) { + return; + } + const res = await defHttp.get( + { url: '/sys/category/loadOne', params: { field: 'code', val: MATERIAL_RAW_AUX_CODE } }, + { isTransformResponse: false }, + ); + if (res?.success && res?.result?.id) { + materialRawAuxCategoryId.value = res.result.id; + } +} + +function normalizeSubmitValues(values: Recordable) { + const payload = { ...values }; + payload.isRubber = isMaterialRawAuxSubCategory(payload.pid) ? toIsRubberFlag(payload.isRubber) : '0'; + return payload; +} + const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { await resetFields(); setModalProps({ confirmLoading: false }); isUpdate.value = !!data?.isUpdate; + await ensureMaterialRawAuxCategoryId(); const tree = await buildPidTree(); if (!tree.length) { createMessage.warning('未加载到物料分类树,请确认分类字典根编码 XSLMES_MATERIAL 已存在'); @@ -89,7 +125,7 @@ const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data if (unref(isUpdate) && data?.record?.id) { const cat = await defHttp.get({ url: '/sys/category/queryById', params: { id: data.record.id } }); - await setFieldsValue({ id: cat.id, pid: cat.pid, name: cat.name }); + await setFieldsValue({ id: cat.id, pid: cat.pid, name: cat.name, isRubber: fromIsRubberFlag(cat.isRubber) }); } else { const pid = data?.parentId != null && data.parentId !== '' ? String(data.parentId) : ''; await setFieldsValue({ pid: pid || undefined, name: '' }); @@ -100,13 +136,13 @@ const title = computed(() => (unref(isUpdate) ? '编辑物料分类' : '新增 async function handleSubmit() { try { - const values = await validate(); + const values = normalizeSubmitValues(await validate()); setModalProps({ confirmLoading: true }); if (unref(isUpdate)) { const full = await defHttp.get({ url: '/sys/category/queryById', params: { id: values.id } }); - await editMaterialSysCategory({ ...full, pid: values.pid, name: values.name }); + await editMaterialSysCategory({ ...full, pid: values.pid, name: values.name, isRubber: values.isRubber }); } else { - await saveMaterialSysCategory({ pid: values.pid, name: values.name }); + await saveMaterialSysCategory({ pid: values.pid, name: values.name, isRubber: values.isRubber }); } closeModal(); emit('success'); diff --git a/jeecgboot-vue3/src/views/system/category/category.constants.ts b/jeecgboot-vue3/src/views/system/category/category.constants.ts new file mode 100644 index 0000000..011798f --- /dev/null +++ b/jeecgboot-vue3/src/views/system/category/category.constants.ts @@ -0,0 +1,22 @@ +import { ref } from 'vue'; + +/** MES 物料分类 - 原辅材料编码 */ +export const MATERIAL_RAW_AUX_CODE = 'XSLMES_MATERIAL_RAW_AUX'; + +/** 原辅材料分类节点 ID(运行时加载) */ +export const materialRawAuxCategoryId = ref(''); + +/** 是否为原辅材料的直接子类 */ +export function isMaterialRawAuxSubCategory(pid?: string) { + return !!materialRawAuxCategoryId.value && pid === materialRawAuxCategoryId.value; +} + +/** 表单 Checkbox 布尔值 -> 数据库存储值 */ +export function toIsRubberFlag(value: unknown) { + return value === true || value === '1' ? '1' : '0'; +} + +/** 数据库存储值 -> 表单 Checkbox 布尔值 */ +export function fromIsRubberFlag(value: unknown) { + return value === '1' || value === 1 || value === true; +} diff --git a/jeecgboot-vue3/src/views/system/category/category.data.ts b/jeecgboot-vue3/src/views/system/category/category.data.ts index 334560e..8adedf2 100644 --- a/jeecgboot-vue3/src/views/system/category/category.data.ts +++ b/jeecgboot-vue3/src/views/system/category/category.data.ts @@ -1,5 +1,6 @@ import { BasicColumn } from '/@/components/Table'; import { FormSchema } from '/@/components/Table'; +import { isMaterialRawAuxSubCategory } from './category.constants'; export const columns: BasicColumn[] = [ { @@ -73,4 +74,13 @@ export const formSchema: FormSchema[] = [ placeholder: '留空将按规则自动生成(如 A01.A02)', }, }, + { + label: ' ', + field: 'isRubber', + component: 'Checkbox', + defaultValue: false, + renderComponentContent: '胶料', + colProps: { span: 24 }, + show: ({ values }) => isMaterialRawAuxSubCategory(values.pid), + }, ]; diff --git a/jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue b/jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue index ee9671e..a59b3e2 100644 --- a/jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue +++ b/jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue @@ -9,12 +9,40 @@ import { BasicForm, useForm } from '/src/components/Form'; import { formSchema } from '../category.data'; import { loadTreeData, saveOrUpdateDict } from '../category.api'; + import { defHttp } from '/@/utils/http/axios'; + import { + MATERIAL_RAW_AUX_CODE, + materialRawAuxCategoryId, + isMaterialRawAuxSubCategory, + toIsRubberFlag, + fromIsRubberFlag, + } from '../category.constants'; + import type { Recordable } from '/@/types/global'; // 获取emit const emit = defineEmits(['register', 'success']); const isUpdate = ref(true); const expandedRowKeys = ref([]); const treeData = ref([]); const isSubAdd = ref(false); + + async function ensureMaterialRawAuxCategoryId() { + if (materialRawAuxCategoryId.value) { + return; + } + const res = await defHttp.get( + { url: '/sys/category/loadOne', params: { field: 'code', val: MATERIAL_RAW_AUX_CODE } }, + { isTransformResponse: false }, + ); + if (res?.success && res?.result?.id) { + materialRawAuxCategoryId.value = res.result.id; + } + } + + function normalizeSubmitValues(values: Recordable) { + const payload = { ...values }; + payload.isRubber = isMaterialRawAuxSubCategory(payload.pid) ? toIsRubberFlag(payload.isRubber) : '0'; + return payload; + } //表单配置 const [registerForm, { resetFields, setFieldsValue, validate, updateSchema }] = useForm({ schemas: formSchema, @@ -35,12 +63,14 @@ expandedRowKeys.value = []; setModalProps({ confirmLoading: false, minHeight: 80 }); isUpdate.value = !!data?.isUpdate; + await ensureMaterialRawAuxCategoryId(); // 代码逻辑说明: 分类字典data.record为空报错------------ isSubAdd.value = !data?.isUpdate && data.record && data.record.id; if (data?.record) { //表单赋值 await setFieldsValue({ ...data.record, + isRubber: fromIsRubberFlag(data.record.isRubber), }); } //父级节点树信息 @@ -76,6 +106,7 @@ async function handleSubmit() { try { let values = await validate(); + values = normalizeSubmitValues(values); setModalProps({ confirmLoading: true }); //提交表单 await saveOrUpdateDict(values, isUpdate.value); diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue new file mode 100644 index 0000000..fe34ebc --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue @@ -0,0 +1,76 @@ + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts index cd57ce4..0c034b7 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts +++ b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts @@ -14,6 +14,8 @@ enum Api { generateRubberCode = '/xslmes/mesXslFormulaSpec/generateRubberCode', getRubberContentSetting = '/xslmes/mesXslFormulaSpec/getRubberContentSetting', saveRubberContentSetting = '/xslmes/mesXslFormulaSpec/saveRubberContentSetting', + buildMixingGeneratePreview = '/xslmes/mesXslFormulaSpec/buildMixingGeneratePreview', + generateMixingSpec = '/xslmes/mesXslFormulaSpec/generateMixingSpec', } export const getExportUrl = Api.exportXls; @@ -41,3 +43,9 @@ export const batchDelete = (params, handleSuccess) => { }; export const saveOrUpdate = (params, isUpdate) => defHttp.post({ url: isUpdate ? Api.edit : Api.save, params }); + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方----------- +export const buildMixingGeneratePreview = (params) => + defHttp.get({ url: Api.buildMixingGeneratePreview, params }, { successMessageMode: 'none' }); +export const generateMixingSpec = (params) => defHttp.post({ url: Api.generateMixingSpec, params }); +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方----------- diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpecList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpecList.vue index 1e000e9..a69c7a8 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpecList.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpecList.vue @@ -36,27 +36,40 @@ + + 生成混炼示方 + + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue index 3cdf834..fe89e22 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue @@ -8,6 +8,17 @@ @register="registerModal" @ok="handleSubmit" > + @@ -439,6 +451,7 @@ } from '../MesXslFormulaSpec.data'; import { saveOrUpdate, queryById, generateRubberCode as generateRubberCodeApi, getRubberContentSetting } from '../MesXslFormulaSpec.api'; import MesXslFormulaRubberContentSettingModal from './MesXslFormulaRubberContentSettingModal.vue'; + import MesXslFormulaGenerateMixingModal from './MesXslFormulaGenerateMixingModal.vue'; import MesXslFormulaLineColumnSetting from './MesXslFormulaLineColumnSetting.vue'; import { queryById as queryMixerById } from '/@/views/mes/material/MesMixerMaterial.api'; import { buildUUID } from '/@/utils/uuid'; @@ -518,6 +531,7 @@ const [registerIssueNumberModal, { openModal: openIssueNumberModalInner }] = useModal(); const [registerIssueDeptModal, { openModal: openIssueDeptModalInner }] = useModal(); const [registerRubberContentSettingModal, { openModal: openRubberContentSettingModal }] = useModal(); + const [registerGenerateMixingModal, { openModal: openGenerateMixingModal }] = useModal(); const issueDeptPickerValue = ref(''); const rubberMaterialPickerId = ref(''); const mixerPsCompilePickerId = ref(''); @@ -1172,6 +1186,19 @@ return !unref(isUpdate) ? '新增配合示方' : '编辑配合示方'; }); + const showGenerateMixingBtn = computed( + () => !showFooterFlag.value && unref(isUpdate) && !!loadedMainRecord.value?.id, + ); + + function handleGenerateMixing() { + const id = loadedMainRecord.value?.id; + if (!id) { + createMessage.warning('请先保存配合示方'); + return; + } + openGenerateMixingModal(true, { formulaSpecId: id }); + } + async function handleLineValueChange(event) { const { row, column } = event || {}; if (!row || !column) { diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixerAction/components/MesXslMixerActionSelectModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixerAction/components/MesXslMixerActionSelectModal.vue new file mode 100644 index 0000000..53439bf --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixerAction/components/MesXslMixerActionSelectModal.vue @@ -0,0 +1,91 @@ + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixerCondition/components/MesXslMixerConditionSelectModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixerCondition/components/MesXslMixerConditionSelectModal.vue new file mode 100644 index 0000000..7865c68 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixerCondition/components/MesXslMixerConditionSelectModal.vue @@ -0,0 +1,91 @@ + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts index e9e089e..415d138 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts @@ -35,7 +35,7 @@ export const columns: BasicColumn[] = [ { title: '机台', align: 'center', dataIndex: 'machineName', width: 120 }, { title: '制作日期', align: 'center', dataIndex: 'makeDate', width: 120 }, { title: '发行编号', align: 'center', dataIndex: 'issueNumber', width: 150 }, - { title: '段数', align: 'center', dataIndex: 'stageCount', width: 80 }, + { title: '段数', align: 'center', dataIndex: 'stageCount', width: 88 }, { title: '纯混炼时间(秒)', align: 'center', dataIndex: 'pureMixSec', width: 130 }, { title: '变更日期', align: 'center', dataIndex: 'changeDate', width: 120 }, { title: '修改时间', align: 'center', dataIndex: 'updateTime', width: 165 }, @@ -49,18 +49,21 @@ export const searchFormSchema: FormSchema[] = [ export const mainSchema: FormSchema[] = [ { label: '', field: 'id', component: 'Input', show: false }, + { label: '', field: 'machineId', component: 'Input', show: false }, { label: '规格', field: 'specName', component: 'Input', required: true, colProps: { span: 8 } }, - { label: '用途', field: 'purpose', component: 'AutoComplete', required: true, colProps: { span: 8 } }, + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A33】混炼示方基本信息字段优化----------- + { label: '用途', field: 'purpose', component: 'Input', required: true, colProps: { span: 8 } }, { label: '机台', field: 'machineName', component: 'Input', colProps: { span: 8 } }, { label: '制作日期', field: 'makeDate', component: 'DatePicker', colProps: { span: 8 }, componentProps: { valueFormat: 'YYYY-MM-DD' } }, - { label: '发行编号', field: 'issueNumber', component: 'AutoComplete', required: true, colProps: { span: 8 } }, + { label: '发行编号', field: 'issueNumber', component: 'Input', required: true, colProps: { span: 8 } }, + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A33】混炼示方基本信息字段优化----------- { label: '换算系数', field: 'convertFactor', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, { label: '填充体积', field: 'fillVolume', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, { label: '回收炭黑(秒)', field: 'recycleCarbonSec', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } }, { label: '母胶比重', field: 'motherRubberSg', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, { label: '终炼胶比重', field: 'finalRubberSg', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, { label: '适用工厂', field: 'applyFactory', component: 'Input', colProps: { span: 8 } }, - { label: '段数', field: 'stageCount', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } }, + { label: '段数', field: 'stageCount', component: 'Input', colProps: { span: 8 }, componentProps: { placeholder: '如 2/3' } }, { label: '纯混炼时间(秒)', field: 'pureMixSec', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } }, { label: '回收炭黑(KG)', field: 'recycleCarbonKg', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, { label: '自动小料打印设定', field: 'autoSmallPrintSetting', component: 'Input', colProps: { span: 8 } }, @@ -198,13 +201,32 @@ export function calcMixingMaterialTableWidth(columns: JVxeColumn[], widthMap: Re export const MIXING_STEP_MIN_COLUMN_WIDTH = 48; export const stepColumns: JVxeColumn[] = [ - { title: '动作', key: 'actionName', type: JVxeTypes.input, width: 120, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH }, + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A35】混合步骤动作/组合列常显下拉倒三角----------- + { + title: '动作', + key: 'actionName', + type: JVxeTypes.slot, + slotName: 'actionNameSlot', + width: 120, + minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, + }, + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A35】混合步骤动作/组合列常显下拉倒三角----------- { title: '时间(")', key: 'actionSec', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, { title: '保护时间', key: 'protectSec', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, { title: '温度(℃)', key: 'tempC', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, { title: '功率(Kw)', key: 'powerKw', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, { title: '能量(Kwh)', key: 'energyKwh', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, - { title: '组合', key: 'comboMode', type: JVxeTypes.input, width: 72, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A35】混合步骤动作/组合列常显下拉倒三角----------- + { + title: '组合', + key: 'comboMode', + type: JVxeTypes.slot, + slotName: 'comboModeSlot', + width: 72, + minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, + align: 'center', + }, + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A35】混合步骤动作/组合列常显下拉倒三角----------- { title: '转速(rpm)', key: 'speedRpm', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, { title: '压力(Mpa)', key: 'pressureMpa', type: JVxeTypes.inputNumber, width: 80, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, { title: '栓(%)', key: 'boltPercent', type: JVxeTypes.inputNumber, width: 72, minWidth: MIXING_STEP_MIN_COLUMN_WIDTH, align: 'center' }, @@ -281,7 +303,9 @@ export const MIXING_TCU_COLUMN_WIDTH_CACHE_KEY = 'mes_xsl_mixing_spec_tcu_column export const MIXING_TCU_MIN_COLUMN_WIDTH = 48; export const tcuColumns: JVxeColumn[] = [ - { title: '区分', key: 'sectionType', type: JVxeTypes.select, dictCode: 'xslmes_mixing_tcu_section', width: 96, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A33】TCU区分固定上/下密炼机----------- + { title: '区分', key: 'sectionType', type: JVxeTypes.select, dictCode: 'xslmes_mixing_tcu_section', disabled: true, width: 96, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, + //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A33】TCU区分固定上/下密炼机----------- { title: '前转子温度', key: 'frontRotorTemp', type: JVxeTypes.inputNumber, width: 76, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, { title: '后转子温度', key: 'rearRotorTemp', type: JVxeTypes.inputNumber, width: 76, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, { title: '前混炼室温度', key: 'frontChamberTemp', type: JVxeTypes.inputNumber, width: 76, minWidth: MIXING_TCU_MIN_COLUMN_WIDTH, align: 'center' }, @@ -580,8 +604,36 @@ export function createEmptyDownStepRows(count = DEFAULT_MIXING_DOWN_STEP_ROW_COU return createEmptyMixingRows(count); } +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A33】TCU默认两行及上密炼机药品称默认值----------- +/** 上密炼机 TCU 行默认药品称量位置(药品称) */ +export const MIXING_TCU_UP_MIXER_DRUG_WEIGH_POS = 'drug_scale'; + +/** 构建 TCU 温度条件默认两行(上密炼机/下密炼机) */ +export function buildDefaultMixingTcuRows(rows: Recordable[] = []): Recordable[] { + const up = + rows.find((r) => r.sectionType === 'up_mixer') || + ({ sectionType: 'up_mixer', drugWeighPos: MIXING_TCU_UP_MIXER_DRUG_WEIGH_POS } as Recordable); + if (up.sectionType === 'up_mixer' && !up.drugWeighPos) { + up.drugWeighPos = MIXING_TCU_UP_MIXER_DRUG_WEIGH_POS; + } + const down = rows.find((r) => r.sectionType === 'down_mixer') || ({ sectionType: 'down_mixer', drugWeighPos: undefined } as Recordable); + return [up, down]; +} +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A33】TCU默认两行及上密炼机药品称默认值----------- + /** 确保明细行具备唯一 id(JVxeTable 依赖 rowKey=id) */ export function normalizeMixingDetailRows(rows: Recordable[] = []): Recordable[] { return (rows || []).map((row) => ({ ...row, id: row?.id || buildUUID() })); } + +//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A39】编辑页明细补齐默认空行与新增一致----------- +/** 编辑/详情加载时补齐明细默认空行(不少于 defaultCount,已有数据行保留) */ +export function ensureMixingDetailRows(rows: Recordable[] = [], defaultCount: number): Recordable[] { + const normalized = normalizeMixingDetailRows(rows); + if (normalized.length >= defaultCount) { + return normalized; + } + return [...normalized, ...createEmptyMixingRows(defaultCount - normalized.length)]; +} +//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A39】编辑页明细补齐默认空行与新增一致----------- //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A22】明细表默认空行数----------- diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue index 4e41b05..d1c244c 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue @@ -28,22 +28,28 @@ 发行编号 - - + @@ -63,16 +69,13 @@ 用途 - 母胶比重 @@ -81,7 +84,13 @@ 段数 - + 纯混炼时间(秒) @@ -253,7 +262,28 @@ :disabled="!showFooter" @resizable-change="handleStepColumnResize" @column-resizable-change="handleStepColumnResize" - /> + > + + + @@ -282,7 +312,28 @@ :disabled="!showFooter" @resizable-change="handleStepColumnResize" @column-resizable-change="handleStepColumnResize" - /> + > + + + @@ -317,13 +368,17 @@ + + + + + From dc3f3053034cec5ee8a6ca73daedb648e573e632 Mon Sep 17 00:00:00 2001 From: geht <2947093423@qq.com> Date: Mon, 25 May 2026 19:44:14 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B7=B7=E7=82=BC?= =?UTF-8?q?=E7=A4=BA=E6=96=B9=EF=BC=8C=E6=96=B0=E5=A2=9E=E7=A7=8D=E7=B1=BB?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 2 + jeecg-boot/.vscode/settings.json | 2 + jeecg-boot/.vscode/tasks.json | 18 + .../jeecg-module-xslmes/doc/代码修改日志 | 93 +++- .../jeecg-module-xslmes/pom.xml | 1 + .../MesXslMixerMaterialKindCfgController.java | 177 +++++++ .../MesXslMixingSpecController.java | 55 ++ .../entity/MesXslMixerMaterialKindCfg.java | 89 ++++ .../MesXslMixerMaterialKindCfgMapper.java | 9 + .../IMesXslMixerMaterialKindCfgService.java | 26 + .../impl/MesXslFormulaSpecServiceImpl.java | 288 ++++++++++- ...MesXslMixerMaterialKindCfgServiceImpl.java | 298 +++++++++++ .../impl/MesXslMixingSpecServiceImpl.java | 472 ++++++++++++++++-- .../service/impl/SysCategoryServiceImpl.java | 28 +- ...2_102__mes_xsl_mixer_material_kind_cfg.sql | 91 ++++ ...s_xsl_mixer_material_kind_cfg_menu_fix.sql | 67 +++ .../MesMixerMaterialSysCategoryModal.vue | 8 +- .../system/category/category.constants.ts | 271 +++++++++- .../views/system/category/category.data.ts | 4 +- .../category/components/CategoryModal.vue | 6 +- .../MesXslEquipmentLedgerMultiSelectModal.vue | 1 + .../MesXslEquipmentLedgerSelectModal.vue | 3 +- .../MesXslFormulaSpec.api.ts | 5 +- .../MesXslMixerMaterialKindCfg.api.ts | 36 ++ .../MesXslMixerMaterialKindCfg.data.ts | 156 ++++++ .../MesXslMixerMaterialKindCfgList.vue | 162 ++++++ .../MesXslMixerMaterialKindCfgBatchModal.vue | 189 +++++++ .../MesXslMixerMaterialKindCfgEditModal.vue | 52 ++ .../mesXslMixingSpec/MesXslMixingSpec.api.ts | 5 +- .../mesXslMixingSpec/MesXslMixingSpec.data.ts | 394 ++++++++++++++- .../MesXslMixingMaterialCategorySetting.vue | 221 ++++++++ .../MesXslMixingMaterialSelectModal.vue | 406 +++++++++++++++ .../components/MesXslMixingSpecModal.vue | 359 ++++++++++++- qhmes.code-workspace | 2 + 34 files changed, 3892 insertions(+), 104 deletions(-) create mode 100644 jeecg-boot/.vscode/tasks.json create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixerMaterialKindCfgController.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixerMaterialKindCfg.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixerMaterialKindCfgMapper.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerMaterialKindCfgService.java create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerMaterialKindCfgServiceImpl.java create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_102__mes_xsl_mixer_material_kind_cfg.sql create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_103__mes_xsl_mixer_material_kind_cfg_menu_fix.sql create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.api.ts create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.data.ts create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfgList.vue create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgBatchModal.vue create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgEditModal.vue create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue diff --git a/.vscode/settings.json b/.vscode/settings.json index ed09f41..71c4c28 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,8 @@ "java.import.maven.enabled": true, "java.configuration.updateBuildConfiguration": "automatic", "java.autobuild.enabled": true, + "java.import.maven.offline.enabled": false, + "java.configuration.maven.notCoveredPluginExecutionSeverity": "ignore", "java.jdt.ls.java.home": "C:\\Program Files\\Java\\jdk-17", "java.configuration.runtimes": [ { diff --git a/jeecg-boot/.vscode/settings.json b/jeecg-boot/.vscode/settings.json index 6dcea9b..28ded36 100644 --- a/jeecg-boot/.vscode/settings.json +++ b/jeecg-boot/.vscode/settings.json @@ -4,6 +4,8 @@ "java.import.maven.enabled": true, "java.configuration.updateBuildConfiguration": "automatic", "java.autobuild.enabled": true, + "java.import.maven.offline.enabled": false, + "java.configuration.maven.notCoveredPluginExecutionSeverity": "ignore", "java.jdt.ls.java.home": "C:\\Program Files\\Java\\jdk-17", "java.configuration.runtimes": [ { diff --git a/jeecg-boot/.vscode/tasks.json b/jeecg-boot/.vscode/tasks.json new file mode 100644 index 0000000..8fd137b --- /dev/null +++ b/jeecg-boot/.vscode/tasks.json @@ -0,0 +1,18 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Maven: 修复 Java Classpath", + "type": "shell", + "command": "mvn clean install -DskipTests -pl jeecg-boot-base-core,jeecg-boot-module/jeecg-module-print,jeecg-boot-module/jeecg-module-xslmes -am", + "options": { + "cwd": "${workspaceFolder}" + }, + "group": { + "kind": "build", + "isDefault": false + }, + "problemMatcher": [] + } + ] +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 index f980ca7..a8cdacb 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 @@ -186,6 +186,95 @@ jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipm jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingStepSelectCell.vue jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue --- author:cursor---date:20260522--for: 【XSLMES-20260522-A37】未选机台点击动作/组合提示请先选择机台 --- -jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingStepSelectCell.vue +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A43】混炼示方换算系数联动橡胶及配合剂单重实时计算 --- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A42】混炼示方橡胶及配合剂明细底部固定合计行 --- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A41】混炼示方橡胶及配合剂明细累计按种类分组合计 --- +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 +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A44】配合示方生成混炼示方时按设备台账有效体积自动计算填充体积 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java +jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A45】混炼示方保存/批量生成子表改批量插入并延长前端超时 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A46】混炼示方换算系数/单重/机台有效体积联动填充体积 --- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerSelectModal.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A47】混炼示方保存分步骤性能诊断日志 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A48】生成混炼示方时同步B/F段胶至密炼物料(母炼胶/A胶、终炼胶/Q胶) --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A49】删除混炼示方时同步删除B/F段胶密炼物料 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】MES物料小类胶料标记/生成混炼示方种类映射/混炼示方选料弹窗 --- +jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java +jeecgboot-vue3/src/views/system/category/category.constants.ts +jeecgboot-vue3/src/views/system/category/category.data.ts +jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue +jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗左侧小类树为空修复(对齐密炼物料列表树加载/异步展开/隐藏配置重置) --- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗小类设置无明细/统一分类加载函数 ----------- +jeecgboot-vue3/src/views/system/category/category.constants.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗分类加载改为getChildListBatch两级查询 ----------- +jeecgboot-vue3/src/views/system/category/category.constants.ts + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗openModal未传data导致初始化未执行 ----------- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗移出父Modal+useModalInner初始化 ----------- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】小类展示分组勾选互不覆盖 ----------- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗隐藏ERP列并新增自动/人工称量列 ----------- +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A51】密炼物料种类配置表及列表批量新增 ----------- +jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_102__mes_xsl_mixer_material_kind_cfg.sql +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixerMaterialKindCfg.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixerMaterialKindCfgMapper.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerMaterialKindCfgService.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerMaterialKindCfgServiceImpl.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixerMaterialKindCfgController.java +jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfgList.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.api.ts +jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgBatchModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgEditModal.vue + +-- author:cursor---date:20260525--for: 【XSLMES-20260525-A51】密炼物料种类配置菜单ID冲突修复 ----------- +jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_102__mes_xsl_mixer_material_kind_cfg.sql +jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_103__mes_xsl_mixer_material_kind_cfg_menu_fix.sql diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/pom.xml b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/pom.xml index e3170f1..e6b3b7f 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/pom.xml +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/pom.xml @@ -17,6 +17,7 @@ org.jeecgframework.boot3 jeecg-boot-base-core + ${jeecgboot.version} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixerMaterialKindCfgController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixerMaterialKindCfgController.java new file mode 100644 index 0000000..f1e86f9 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixerMaterialKindCfgController.java @@ -0,0 +1,177 @@ +package org.jeecg.modules.xslmes.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.util.Arrays; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.aspect.annotation.AutoLog; +import org.jeecg.common.constant.CommonConstant; +import org.jeecg.common.system.base.controller.JeecgController; +import org.jeecg.common.system.query.QueryGenerator; +import org.jeecg.common.util.oConvertUtils; +import org.jeecg.modules.xslmes.entity.MesXslMixerMaterialKindCfg; +import org.jeecg.modules.xslmes.service.IMesXslMixerMaterialKindCfgService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +/** + * MES 密炼物料种类配置 + */ +@Tag(name = "MES密炼物料种类配置") +@RestController +@RequestMapping("/xslmes/mesXslMixerMaterialKindCfg") +@Slf4j +public class MesXslMixerMaterialKindCfgController + extends JeecgController { + + @Autowired + private IMesXslMixerMaterialKindCfgService mesXslMixerMaterialKindCfgService; + + @Operation(summary = "MES密炼物料种类配置-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList( + MesXslMixerMaterialKindCfg model, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, + HttpServletRequest req) { + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap()); + queryWrapper.orderByAsc("priority").orderByDesc("create_time"); + Page page = new Page<>(pageNo, pageSize); + IPage pageList = mesXslMixerMaterialKindCfgService.page(page, queryWrapper); + return Result.OK(pageList); + } + + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置展开与批量保存----------- + @Operation(summary = "MES密炼物料种类配置-按根字典/分类展开明细") + @GetMapping(value = "/expandLines") + public Result> expandLines( + @RequestParam(name = "sourceType") String sourceType, + @RequestParam(name = "sourceRootCode") String sourceRootCode, + @RequestParam(name = "tenantId", required = false) Integer tenantId) { + List lines = + mesXslMixerMaterialKindCfgService.expandLines(sourceType, sourceRootCode, tenantId); + return Result.OK(lines); + } + + @AutoLog(value = "MES密炼物料种类配置-批量添加") + @Operation(summary = "MES密炼物料种类配置-批量添加") + @RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:add") + @PostMapping(value = "/addBatch") + public Result addBatch(@RequestBody List lines) { + mesXslMixerMaterialKindCfgService.saveBatchLines(lines, null); + return Result.OK("添加成功!"); + } + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置展开与批量保存----------- + + @AutoLog(value = "MES密炼物料种类配置-添加") + @Operation(summary = "MES密炼物料种类配置-添加") + @RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:add") + @PostMapping(value = "/add") + public Result add(@RequestBody MesXslMixerMaterialKindCfg model) { + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验----------- + String err = validateForSave(model, false); + if (err != null) { + return Result.error(err); + } + model.setDelFlag(CommonConstant.DEL_FLAG_0); + mesXslMixerMaterialKindCfgService.save(model); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验----------- + return Result.OK("添加成功!"); + } + + @AutoLog(value = "MES密炼物料种类配置-编辑") + @Operation(summary = "MES密炼物料种类配置-编辑") + @RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:edit") + @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST}) + public Result edit(@RequestBody MesXslMixerMaterialKindCfg model) { + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验----------- + String err = validateForSave(model, true); + if (err != null) { + return Result.error(err); + } + mesXslMixerMaterialKindCfgService.updateById(model); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验----------- + return Result.OK("编辑成功!"); + } + + @AutoLog(value = "MES密炼物料种类配置-删除") + @Operation(summary = "MES密炼物料种类配置-通过id删除") + @RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:delete") + @DeleteMapping(value = "/delete") + public Result delete(@RequestParam(name = "id", required = true) String id) { + mesXslMixerMaterialKindCfgService.removeById(id); + return Result.OK("删除成功!"); + } + + @AutoLog(value = "MES密炼物料种类配置-批量删除") + @Operation(summary = "MES密炼物料种类配置-批量删除") + @RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:deleteBatch") + @DeleteMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) { + mesXslMixerMaterialKindCfgService.removeByIds(Arrays.asList(ids.split(","))); + return Result.OK("批量删除成功!"); + } + + @Operation(summary = "MES密炼物料种类配置-通过id查询") + @GetMapping(value = "/queryById") + public Result queryById(@RequestParam(name = "id", required = true) String id) { + MesXslMixerMaterialKindCfg entity = mesXslMixerMaterialKindCfgService.getById(id); + if (entity == null) { + return Result.error("未找到对应数据"); + } + return Result.OK(entity); + } + + @RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:exportXls") + @RequestMapping(value = "/exportXls") + public ModelAndView exportXls(HttpServletRequest request, MesXslMixerMaterialKindCfg model) { + return super.exportXls(request, model, MesXslMixerMaterialKindCfg.class, "密炼物料种类配置"); + } + + @RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:importExcel") + @RequestMapping(value = "/importExcel", method = RequestMethod.POST) + public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + return super.importExcel(request, response, MesXslMixerMaterialKindCfg.class); + } + + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验----------- + private String validateForSave(MesXslMixerMaterialKindCfg model, boolean isUpdate) { + if (model == null) { + return "参数不能为空"; + } + if (oConvertUtils.isEmpty(model.getKindKey())) { + return "种类键值不能为空"; + } + if (oConvertUtils.isEmpty(model.getKindName())) { + return "种类名称不能为空"; + } + if (oConvertUtils.isEmpty(model.getSourceType())) { + return "数据源类型不能为空"; + } + if (oConvertUtils.isEmpty(model.getCategoryRefId())) { + return "对应分类不能为空"; + } + if (model.getPriority() == null) { + model.setPriority(999); + } + if (isUpdate && oConvertUtils.isEmpty(model.getId())) { + return "主键不能为空"; + } + try { + mesXslMixerMaterialKindCfgService.checkDuplicate(model, isUpdate ? model.getId() : null); + } catch (Exception e) { + return e.getMessage(); + } + return null; + } + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验----------- +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java index 52700e2..f35e9ef 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java @@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpServletResponse; import java.util.Arrays; import java.util.List; import java.util.Map; +import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.AutoLog; @@ -30,6 +31,7 @@ import org.springframework.web.servlet.ModelAndView; @Tag(name = "MES混炼示方") @RestController @RequestMapping("/xslmes/mesXslMixingSpec") +@Slf4j public class MesXslMixingSpecController extends JeecgController { @Autowired @@ -59,13 +61,36 @@ public class MesXslMixingSpecController extends JeecgController add(@RequestBody MesXslMixingSpecPage page) { + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- + long requestStartMs = System.currentTimeMillis(); + log.info( + "[混炼示方保存性能] 接口/add 收到请求 specName={}, payload=[material={}, step={}, downStep={}, tcu={}]", + page != null ? page.getSpecName() : null, + countChildRows(page != null ? page.getMaterialList() : null), + countChildRows(page != null ? page.getStepList() : null), + countChildRows(page != null ? page.getDownStepList() : null), + countChildRows(page != null ? page.getTcuList() : null)); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- String err = validateMain(page); if (err != null) { return Result.error(err); } + long validateMs = System.currentTimeMillis(); MesXslMixingSpec main = new MesXslMixingSpec(); BeanUtils.copyProperties(page, main); + long copyMs = System.currentTimeMillis(); mesXslMixingSpecService.saveMain(main, page.getMaterialList(), page.getStepList(), page.getDownStepList(), page.getTcuList()); + long serviceMs = System.currentTimeMillis(); + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- + log.info( + "[混炼示方保存性能] 接口/add 完成 specName={}, mainId={}, validate={}ms, copy={}ms, service={}ms, total={}ms(返回响应前,不含AutoLog等切面)", + main.getSpecName(), + main.getId(), + validateMs - requestStartMs, + copyMs - validateMs, + serviceMs - copyMs, + serviceMs - requestStartMs); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- return Result.OK("添加成功!"); } @@ -74,13 +99,37 @@ public class MesXslMixingSpecController extends JeecgController edit(@RequestBody MesXslMixingSpecPage page) { + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- + long requestStartMs = System.currentTimeMillis(); + log.info( + "[混炼示方保存性能] 接口/edit 收到请求 id={}, specName={}, payload=[material={}, step={}, downStep={}, tcu={}]", + page != null ? page.getId() : null, + page != null ? page.getSpecName() : null, + countChildRows(page != null ? page.getMaterialList() : null), + countChildRows(page != null ? page.getStepList() : null), + countChildRows(page != null ? page.getDownStepList() : null), + countChildRows(page != null ? page.getTcuList() : null)); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- String err = validateMain(page); if (err != null) { return Result.error(err); } + long validateMs = System.currentTimeMillis(); MesXslMixingSpec main = new MesXslMixingSpec(); BeanUtils.copyProperties(page, main); + long copyMs = System.currentTimeMillis(); mesXslMixingSpecService.updateMain(main, page.getMaterialList(), page.getStepList(), page.getDownStepList(), page.getTcuList()); + long serviceMs = System.currentTimeMillis(); + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- + log.info( + "[混炼示方保存性能] 接口/edit 完成 id={}, specName={}, validate={}ms, copy={}ms, service={}ms, total={}ms(返回响应前,不含AutoLog等切面)", + main.getId(), + main.getSpecName(), + validateMs - requestStartMs, + copyMs - validateMs, + serviceMs - copyMs, + serviceMs - requestStartMs); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- return Result.OK("编辑成功!"); } @@ -151,5 +200,11 @@ public class MesXslMixingSpecController extends JeecgController rows) { + return rows == null ? 0 : rows.size(); + } + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子保存校验----------- } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixerMaterialKindCfg.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixerMaterialKindCfg.java new file mode 100644 index 0000000..f1b5188 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixerMaterialKindCfg.java @@ -0,0 +1,89 @@ +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.util.Date; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.springframework.format.annotation.DateTimeFormat; + +/** + * MES 密炼物料种类配置 + */ +@Data +@TableName("mes_xsl_mixer_material_kind_cfg") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "MES密炼物料种类配置") +public class MesXslMixerMaterialKindCfg implements Serializable { + + private static final long serialVersionUID = 1L; + + public static final String SOURCE_TYPE_DICT = "dict"; + public static final String SOURCE_TYPE_CATEGORY = "category"; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Excel(name = "种类键值", width = 15) + @Schema(description = "种类键值") + private String kindKey; + + @Excel(name = "种类名称", width = 20) + @Schema(description = "种类名称") + private String kindName; + + @Excel(name = "数据源类型", width = 12) + @Schema(description = "数据源类型:dict/category") + private String sourceType; + + @Excel(name = "根编码", width = 15) + @Schema(description = "根字典编码或分类pcode") + private String sourceRootCode; + + @Excel(name = "根名称", width = 20) + @Schema(description = "根名称冗余") + private String sourceRootName; + + @Schema(description = "对应分类/字典项ID") + private String categoryRefId; + + @Excel(name = "对应编码", width = 15) + @Schema(description = "对应分类编码/字典项值") + private String categoryRefCode; + + @Excel(name = "对应分类", width = 20) + @Schema(description = "对应分类名称冗余") + private String categoryRefName; + + @Excel(name = "优先级", width = 10) + @Schema(description = "优先级(数字越小越优先)") + private Integer priority; + + @Schema(description = "租户ID") + private Integer tenantId; + + private String sysOrgCode; + + @Excel(name = "创建人", width = 15) + private String createBy; + + @Excel(name = "创建时间", width = 20, format = "yyyy-MM-dd HH:mm:ss") + @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; + + private Integer delFlag; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixerMaterialKindCfgMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixerMaterialKindCfgMapper.java new file mode 100644 index 0000000..b938f65 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixerMaterialKindCfgMapper.java @@ -0,0 +1,9 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslMixerMaterialKindCfg; + +/** + * MES 密炼物料种类配置 + */ +public interface MesXslMixerMaterialKindCfgMapper extends BaseMapper {} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerMaterialKindCfgService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerMaterialKindCfgService.java new file mode 100644 index 0000000..83a7593 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerMaterialKindCfgService.java @@ -0,0 +1,26 @@ +package org.jeecg.modules.xslmes.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import java.util.List; +import org.jeecg.modules.xslmes.entity.MesXslMixerMaterialKindCfg; + +/** + * MES 密炼物料种类配置 + */ +public interface IMesXslMixerMaterialKindCfgService extends IService { + + /** + * 按根字典/分类展开明细行(未持久化) + */ + List expandLines(String sourceType, String sourceRootCode, Integer tenantId); + + /** + * 批量新增 + */ + void saveBatchLines(List lines, Integer tenantId); + + /** + * 校验租户内种类键值/对应分类是否重复 + */ + void checkDuplicate(MesXslMixerMaterialKindCfg line, String excludeId); +} 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 883b7f0..5f96f9a 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 @@ -24,9 +24,11 @@ import org.jeecg.modules.mes.material.entity.MesMaterial; import org.jeecg.modules.mes.material.entity.MesMixerMaterial; import org.jeecg.modules.mes.material.service.IMesMaterialService; import org.jeecg.modules.mes.material.service.IMesMixerMaterialService; +import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.util.oConvertUtils; import org.jeecg.modules.system.entity.SysCategory; import org.jeecg.modules.system.service.ISysCategoryService; +import org.jeecg.modules.xslmes.entity.MesXslEquipmentLedger; import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec; import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine; import org.jeecg.modules.xslmes.entity.MesXslMixerPsCompile; @@ -34,6 +36,7 @@ import org.jeecg.modules.xslmes.entity.MesXslMixingSpec; import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial; import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecLineMapper; import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecMapper; +import org.jeecg.modules.xslmes.service.IMesXslEquipmentLedgerService; import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecService; import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecSettingService; import org.jeecg.modules.xslmes.service.IMesXslMixingSpecService; @@ -44,16 +47,24 @@ import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateRequestVO; import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateRowVO; import org.jeecg.modules.system.entity.SysUser; import org.jeecg.modules.system.service.ISysUserService; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @Service +@Slf4j public class MesXslFormulaSpecServiceImpl extends ServiceImpl implements IMesXslFormulaSpecService { private static final Set RUBBER_CATEGORY_KEYS = Set.of("S", "P", "T", "C"); private static final Pattern RUBBER_CODE_VERSION_PATTERN = Pattern.compile("([A-Z])01$"); + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料----------- + private static final String CATEGORY_MASTER_MAJOR = "XSLMES_MATERIAL_MASTER"; + private static final String CATEGORY_MASTER_MINOR_A = "XSLMES_MATERIAL_MASTER_A"; + private static final String CATEGORY_FINAL_MAJOR = "XSLMES_MATERIAL_FINAL"; + private static final String CATEGORY_FINAL_MINOR_Q = "XSLMES_MATERIAL_FINAL_Q"; + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料----------- @Resource private MesXslFormulaSpecLineMapper lineMapper; @@ -73,6 +84,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl mixerCache = new HashMap<>(); Map categoryNameCache = new HashMap<>(); Map categoryRubberCache = new HashMap<>(); + Map equipmentCache = new HashMap<>(); + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】F段终炼胶比重按配合示方整体PHR/体积汇总----------- + BigDecimal compoundSpecificGravity = resolveCompoundSpecificGravity(formula, lines); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】F段终炼胶比重按配合示方整体PHR/体积汇总----------- int created = 0; int totalStages = normalizeMixingStages(formula.getMixingStages()); Date today = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()); + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料----------- + Set syncedRubberSpecCodes = new HashSet<>(); + Map categoryIdCache = new HashMap<>(); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料----------- for (MesXslFormulaMixingGenerateRowVO row : request.getRows()) { if (row == null || oConvertUtils.isEmpty(row.getSpecCode()) || row.getStageIndex() == null) { continue; @@ -525,6 +547,11 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl materials = buildMixingMaterials( @@ -547,11 +574,25 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl lines) { + if (CollectionUtils.isEmpty(lines)) { + return null; + } + BigDecimal totalPhr = formula != null && formula.getTotalPhr() != null && formula.getTotalPhr().compareTo(BigDecimal.ZERO) > 0 + ? formula.getTotalPhr() + : BigDecimal.ZERO; + if (totalPhr.compareTo(BigDecimal.ZERO) <= 0) { + for (MesXslFormulaSpecLine line : lines) { + if (line != null && line.getPhr() != null) { + totalPhr = totalPhr.add(line.getPhr()); + } + } + } + BigDecimal totalVolume = BigDecimal.ZERO; + for (MesXslFormulaSpecLine line : lines) { + BigDecimal volume = resolveLineVolume(line); + if (volume != null) { + totalVolume = totalVolume.add(volume); + } + } + if (totalPhr.compareTo(BigDecimal.ZERO) <= 0 || totalVolume.compareTo(BigDecimal.ZERO) <= 0) { + return null; + } + return totalPhr.divide(totalVolume, 6, RoundingMode.HALF_UP); + } + + /** 解析设备台账有效体积(支持纯数字或带单位的字符串) */ + private BigDecimal parseEffectiveVolume(String raw, String machineLabel) { + if (StringUtils.isBlank(raw)) { + throw new IllegalArgumentException("机台「" + machineLabel + "」未维护有效体积,无法计算填充体积"); + } + String trimmed = raw.trim(); + try { + BigDecimal value = new BigDecimal(trimmed); + if (value.compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("机台「" + machineLabel + "」有效体积必须大于 0"); + } + return value; + } catch (NumberFormatException ignored) { + Matcher matcher = Pattern.compile("([0-9]+(?:\\.[0-9]+)?)").matcher(trimmed); + if (matcher.find()) { + BigDecimal value = new BigDecimal(matcher.group(1)); + if (value.compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("机台「" + machineLabel + "」有效体积必须大于 0"); + } + return value; + } + throw new IllegalArgumentException("机台「" + machineLabel + "」有效体积格式无效:" + raw); + } + } + + /** 橡胶及配合剂明细单重合计 */ + private BigDecimal sumMaterialUnitWeight(List materials) { + if (CollectionUtils.isEmpty(materials)) { + return BigDecimal.ZERO; + } + BigDecimal total = BigDecimal.ZERO; + for (MesXslMixingSpecMaterial material : materials) { + if (material != null && material.getUnitWeight() != null) { + total = total.add(material.getUnitWeight()); + } + } + return total; + } + + /** + * 填充体积(%) = 本段单重合计 ÷ 本段比重 ÷ 机台有效体积(L) × 100 × 换算系数 + */ + private BigDecimal calcFillVolume( + BigDecimal totalWeight, + BigDecimal specificGravity, + BigDecimal effectiveVolume, + BigDecimal convertFactor) { + if (totalWeight == null || totalWeight.compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("本段橡胶及配合剂单重合计无效,无法计算填充体积"); + } + if (specificGravity == null || specificGravity.compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("本段比重无效,无法计算填充体积"); + } + if (effectiveVolume == null || effectiveVolume.compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("机台有效体积无效,无法计算填充体积"); + } + BigDecimal factor = convertFactor == null || convertFactor.compareTo(BigDecimal.ZERO) <= 0 + ? BigDecimal.ONE + : convertFactor; + BigDecimal materialVolume = totalWeight.divide(specificGravity, 6, RoundingMode.HALF_UP); + return materialVolume + .divide(effectiveVolume, 6, RoundingMode.HALF_UP) + .multiply(BigDecimal.valueOf(100)) + .multiply(factor) + .setScale(6, RoundingMode.HALF_UP); + } + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】生成混炼示方时按设备有效体积计算填充体积----------- + + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料----------- + /** + * 生成混炼示方时,将 B 段/F 段胶料同步写入密炼物料: + * B 段 -> 物料大类「母炼胶」+ 小类「A胶」;F 段 -> 物料大类「终炼胶」+ 小类「Q胶」。 + */ + private void syncGeneratedRubberMixerMaterial( + MesXslFormulaMixingGenerateRowVO row, + MesXslFormulaSpec formula, + BigDecimal compoundSpecificGravity, + Map categoryIdCache) { + if (row == null || StringUtils.isBlank(row.getSpecCode())) { + return; + } + String specCode = row.getSpecCode().trim(); + boolean isFinalStage = "Q".equalsIgnoreCase(resolveMixingMaterialStep(row)); + String majorCode = isFinalStage ? CATEGORY_FINAL_MAJOR : CATEGORY_MASTER_MAJOR; + String minorCode = isFinalStage ? CATEGORY_FINAL_MINOR_Q : CATEGORY_MASTER_MINOR_A; + String majorCategoryId = resolveCategoryIdByCode(majorCode, categoryIdCache); + String minorCategoryId = resolveCategoryIdByCode(minorCode, categoryIdCache); + if (StringUtils.isBlank(majorCategoryId) || StringUtils.isBlank(minorCategoryId)) { + throw new IllegalArgumentException( + "未找到物料分类「" + (isFinalStage ? "终炼胶/Q胶" : "母炼胶/A胶") + "」,请先维护 MES 物料分类字典"); + } + BigDecimal specificGravity = isFinalStage ? compoundSpecificGravity : formula.getARubberSg(); + String rubberName = resolveRubberName(formula); + String materialDesc = StringUtils.isNotBlank(formula.getPurpose()) ? formula.getPurpose().trim() : rubberName; + + MesMixerMaterial existing = findMixerMaterialByCodeOrName(specCode); + Date now = new Date(); + if (existing != null) { + existing.setMajorCategoryId(majorCategoryId); + existing.setMinorCategoryId(minorCategoryId); + existing.setSpecificGravity(specificGravity); + if (StringUtils.isNotBlank(materialDesc)) { + existing.setMaterialDesc(materialDesc); + } + if (StringUtils.isBlank(existing.getMaterialCode())) { + existing.setMaterialCode(specCode); + } + if (StringUtils.isBlank(existing.getMaterialName())) { + existing.setMaterialName(specCode); + } + existing.setUseStatus(existing.getUseStatus() == null ? 1 : existing.getUseStatus()); + existing.setUpdateTime(now); + mesMixerMaterialService.updateById(existing); + log.info( + "[混炼示方生成] 更新密炼物料 id={}, code={}, major={}, minor={}, sg={}", + existing.getId(), + specCode, + majorCode, + minorCode, + specificGravity); + return; + } + + MesMixerMaterial material = new MesMixerMaterial(); + material.setMaterialCode(specCode); + material.setMaterialName(specCode); + material.setMaterialDesc(materialDesc); + material.setAliasName(StringUtils.isNotBlank(rubberName) ? rubberName : null); + material.setMajorCategoryId(majorCategoryId); + material.setMinorCategoryId(minorCategoryId); + material.setSpecificGravity(specificGravity); + material.setFeedManageStatus(0); + material.setUseStatus(1); + material.setDelFlag(CommonConstant.DEL_FLAG_0); + material.setCreateTime(now); + material.setUpdateTime(now); + mesMixerMaterialService.save(material); + log.info( + "[混炼示方生成] 新增密炼物料 id={}, code={}, major={}, minor={}, sg={}", + material.getId(), + specCode, + majorCode, + minorCode, + specificGravity); + } + + private MesMixerMaterial findMixerMaterialByCodeOrName(String specCode) { + MesMixerMaterial byCode = mesMixerMaterialService.getOne( + new LambdaQueryWrapper() + .eq(MesMixerMaterial::getMaterialCode, specCode) + .and(w -> w.eq(MesMixerMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMixerMaterial::getDelFlag)) + .last("limit 1")); + if (byCode != null) { + return byCode; + } + return mesMixerMaterialService.getOne( + new LambdaQueryWrapper() + .eq(MesMixerMaterial::getMaterialName, specCode) + .and(w -> w.eq(MesMixerMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMixerMaterial::getDelFlag)) + .last("limit 1")); + } + + private String resolveCategoryIdByCode(String categoryCode, Map cache) { + if (StringUtils.isBlank(categoryCode)) { + return null; + } + if (cache != null && cache.containsKey(categoryCode)) { + return cache.get(categoryCode); + } + SysCategory category = sysCategoryService.getOne( + new LambdaQueryWrapper().eq(SysCategory::getCode, categoryCode.trim()).last("limit 1")); + String categoryId = category != null ? category.getId() : null; + if (cache != null) { + cache.put(categoryCode, categoryId); + } + return categoryId; + } + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料----------- + private int normalizeMixingStages(Integer mixingStages) { if (mixingStages == null || mixingStages <= 0) { return 0; @@ -861,7 +1110,7 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl mixerCache, Map categoryNameCache, Map categoryRubberCache) { @@ -894,18 +1144,27 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl categoryRubberCache) { + String weighMode, String minorCategoryId, String minorCategoryName, Map categoryRubberCache) { + String weighKind = resolveWeighModeMaterialKind(weighMode); + if (StringUtils.isNotBlank(weighKind)) { + return weighKind; + } if (isCategoryRubber(minorCategoryId, categoryRubberCache)) { return "胶料"; } @@ -915,6 +1174,23 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl 混炼示方种类 */ + private String resolveWeighModeMaterialKind(String weighMode) { + if (StringUtils.isBlank(weighMode)) { + return null; + } + String normalized = weighMode.trim(); + String lower = normalized.toLowerCase(); + if (lower.startsWith("auto") || normalized.contains("自动")) { + return "自动"; + } + if ("manual".equals(lower) || normalized.contains("人工")) { + return "人工"; + } + return null; + } + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】生成混炼示方时称量方式优先映射种类----------- + private boolean isCategoryRubber(String categoryId, Map cache) { if (oConvertUtils.isEmpty(categoryId)) { return false; diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerMaterialKindCfgServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerMaterialKindCfgServiceImpl.java new file mode 100644 index 0000000..306c3e4 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerMaterialKindCfgServiceImpl.java @@ -0,0 +1,298 @@ +package org.jeecg.modules.xslmes.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.servlet.http.HttpServletRequest; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.jeecg.common.constant.CommonConstant; +import org.jeecg.common.exception.JeecgBootException; +import org.jeecg.common.util.SpringContextUtils; +import org.jeecg.common.util.TokenUtils; +import org.jeecg.common.util.oConvertUtils; +import org.jeecg.common.config.TenantContext; +import org.jeecg.config.mybatis.MybatisPlusSaasConfig; +import org.jeecg.modules.system.entity.SysCategory; +import org.jeecg.modules.system.entity.SysDict; +import org.jeecg.modules.system.entity.SysDictItem; +import org.jeecg.modules.system.service.ISysCategoryService; +import org.jeecg.modules.system.service.ISysDictItemService; +import org.jeecg.modules.system.service.ISysDictService; +import org.jeecg.modules.xslmes.entity.MesXslMixerMaterialKindCfg; +import org.jeecg.modules.xslmes.mapper.MesXslMixerMaterialKindCfgMapper; +import org.jeecg.modules.xslmes.service.IMesXslMixerMaterialKindCfgService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * MES 密炼物料种类配置 + */ +@Service +public class MesXslMixerMaterialKindCfgServiceImpl + extends ServiceImpl + implements IMesXslMixerMaterialKindCfgService { + + @Autowired + private ISysDictService sysDictService; + + @Autowired + private ISysDictItemService sysDictItemService; + + @Autowired + private ISysCategoryService sysCategoryService; + + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置展开与批量保存----------- + @Override + public List expandLines(String sourceType, String sourceRootCode, Integer tenantId) { + if (oConvertUtils.isEmpty(sourceType) || oConvertUtils.isEmpty(sourceRootCode)) { + throw new JeecgBootException("请选择数据源类型与根字典/分类"); + } + String normalizedType = sourceType.trim().toLowerCase(); + String rootCode = sourceRootCode.trim(); + if (MesXslMixerMaterialKindCfg.SOURCE_TYPE_DICT.equals(normalizedType)) { + return expandFromDict(rootCode, tenantId); + } + if (MesXslMixerMaterialKindCfg.SOURCE_TYPE_CATEGORY.equals(normalizedType)) { + return expandFromCategory(rootCode, tenantId); + } + throw new JeecgBootException("不支持的数据源类型:" + sourceType); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveBatchLines(List lines, Integer tenantId) { + if (lines == null || lines.isEmpty()) { + throw new JeecgBootException("请至少维护一条种类配置明细"); + } + Integer resolvedTenantId = resolveTenantId(tenantId); + Set kindKeys = new HashSet<>(); + Set categoryRefIds = new HashSet<>(); + for (MesXslMixerMaterialKindCfg line : lines) { + String err = validateLine(line, kindKeys, categoryRefIds); + if (err != null) { + throw new JeecgBootException(err); + } + line.setTenantId(resolvedTenantId); + line.setDelFlag(CommonConstant.DEL_FLAG_0); + checkDuplicate(line, null); + } + saveBatch(lines); + } + + private List expandFromDict(String dictCode, Integer tenantId) { + LambdaQueryWrapper dictQw = new LambdaQueryWrapper<>(); + dictQw.eq(SysDict::getDictCode, dictCode); + SysDict dict = sysDictService.getOne(dictQw, false); + if (dict == null) { + throw new JeecgBootException("数据字典不存在:" + dictCode); + } + LambdaQueryWrapper itemQw = new LambdaQueryWrapper<>(); + itemQw.eq(SysDictItem::getDictId, dict.getId()); + itemQw.eq(SysDictItem::getStatus, 1); + itemQw.orderByAsc(SysDictItem::getSortOrder).orderByAsc(SysDictItem::getItemValue); + List items = sysDictItemService.list(itemQw); + if (items == null || items.isEmpty()) { + throw new JeecgBootException("该数据字典下没有可用的字典项"); + } + Set existsRefIds = loadExistingCategoryRefIds(MesXslMixerMaterialKindCfg.SOURCE_TYPE_DICT, dictCode, tenantId); + List result = new ArrayList<>(); + int priorityBase = 10; + int index = 0; + for (SysDictItem item : items) { + if (item == null || oConvertUtils.isEmpty(item.getId())) { + continue; + } + if (existsRefIds.contains(item.getId())) { + continue; + } + MesXslMixerMaterialKindCfg cfg = new MesXslMixerMaterialKindCfg(); + cfg.setSourceType(MesXslMixerMaterialKindCfg.SOURCE_TYPE_DICT); + cfg.setSourceRootCode(dictCode); + cfg.setSourceRootName(dict.getDictName()); + cfg.setCategoryRefId(item.getId()); + cfg.setCategoryRefCode(item.getItemValue()); + cfg.setCategoryRefName(item.getItemText()); + cfg.setKindKey(item.getItemValue()); + cfg.setKindName(item.getItemText()); + cfg.setPriority(item.getSortOrder() != null ? item.getSortOrder() : priorityBase + index * 10); + cfg.setTenantId(resolveTenantId(tenantId)); + result.add(cfg); + index++; + } + if (result.isEmpty()) { + throw new JeecgBootException("该数据字典下的字典项均已配置,无需重复带出"); + } + return result; + } + + private List expandFromCategory(String rootCode, Integer tenantId) { + LambdaQueryWrapper rootQw = new LambdaQueryWrapper<>(); + rootQw.eq(SysCategory::getCode, rootCode); + SysCategory root = sysCategoryService.getOne(rootQw, false); + if (root == null) { + throw new JeecgBootException("分类字典不存在:" + rootCode); + } + List descendants = new ArrayList<>(); + Deque queue = new ArrayDeque<>(); + queue.add(root.getId()); + while (!queue.isEmpty()) { + String parentId = queue.poll(); + LambdaQueryWrapper childQw = new LambdaQueryWrapper<>(); + childQw.eq(SysCategory::getPid, parentId); + childQw.orderByAsc(SysCategory::getCode); + List children = sysCategoryService.list(childQw); + if (children == null || children.isEmpty()) { + continue; + } + for (SysCategory child : children) { + descendants.add(child); + queue.add(child.getId()); + } + } + if (descendants.isEmpty()) { + throw new JeecgBootException("该分类下没有可用的子分类"); + } + Set existsRefIds = loadExistingCategoryRefIds(MesXslMixerMaterialKindCfg.SOURCE_TYPE_CATEGORY, rootCode, tenantId); + List result = new ArrayList<>(); + int priorityBase = 10; + for (int i = 0; i < descendants.size(); i++) { + SysCategory category = descendants.get(i); + if (category == null || oConvertUtils.isEmpty(category.getId())) { + continue; + } + if (existsRefIds.contains(category.getId())) { + continue; + } + String refCode = oConvertUtils.isNotEmpty(category.getCode()) ? category.getCode() : category.getId(); + MesXslMixerMaterialKindCfg cfg = new MesXslMixerMaterialKindCfg(); + cfg.setSourceType(MesXslMixerMaterialKindCfg.SOURCE_TYPE_CATEGORY); + cfg.setSourceRootCode(rootCode); + cfg.setSourceRootName(root.getName()); + cfg.setCategoryRefId(category.getId()); + cfg.setCategoryRefCode(refCode); + cfg.setCategoryRefName(category.getName()); + cfg.setKindKey(refCode); + cfg.setKindName(category.getName()); + cfg.setPriority(priorityBase + i * 10); + cfg.setTenantId(resolveTenantId(tenantId)); + result.add(cfg); + } + if (result.isEmpty()) { + throw new JeecgBootException("该分类下的子分类均已配置,无需重复带出"); + } + return result; + } + + private Set loadExistingCategoryRefIds(String sourceType, String sourceRootCode, Integer tenantId) { + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(MesXslMixerMaterialKindCfg::getSourceType, sourceType); + qw.eq(MesXslMixerMaterialKindCfg::getSourceRootCode, sourceRootCode); + qw.and(q -> q.eq(MesXslMixerMaterialKindCfg::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesXslMixerMaterialKindCfg::getDelFlag)); + Integer resolvedTenantId = resolveTenantId(tenantId); + if (resolvedTenantId != null && MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) { + qw.eq(MesXslMixerMaterialKindCfg::getTenantId, resolvedTenantId); + } + qw.select(MesXslMixerMaterialKindCfg::getCategoryRefId); + List exists = list(qw); + Set ids = new HashSet<>(); + if (exists != null) { + for (MesXslMixerMaterialKindCfg row : exists) { + if (row != null && oConvertUtils.isNotEmpty(row.getCategoryRefId())) { + ids.add(row.getCategoryRefId()); + } + } + } + return ids; + } + + private String validateLine(MesXslMixerMaterialKindCfg line, Set kindKeys, Set categoryRefIds) { + if (line == null) { + return "存在空的明细行"; + } + if (oConvertUtils.isEmpty(line.getKindKey())) { + return "种类键值不能为空"; + } + if (oConvertUtils.isEmpty(line.getKindName())) { + return "种类名称不能为空"; + } + if (oConvertUtils.isEmpty(line.getSourceType())) { + return "数据源类型不能为空"; + } + if (oConvertUtils.isEmpty(line.getCategoryRefId())) { + return "对应分类不能为空"; + } + String kindKey = line.getKindKey().trim(); + if (!kindKeys.add(kindKey)) { + return "本次提交存在重复的种类键值:" + kindKey; + } + String refId = line.getCategoryRefId().trim(); + if (!categoryRefIds.add(refId)) { + return "本次提交存在重复的对应分类"; + } + if (line.getPriority() == null) { + line.setPriority(999); + } + return null; + } + + @Override + public void checkDuplicate(MesXslMixerMaterialKindCfg line, String excludeId) { + Integer tenantId = resolveTenantId(line.getTenantId()); + LambdaQueryWrapper kindQw = new LambdaQueryWrapper<>(); + kindQw.eq(MesXslMixerMaterialKindCfg::getKindKey, line.getKindKey().trim()); + kindQw.and(q -> q.eq(MesXslMixerMaterialKindCfg::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesXslMixerMaterialKindCfg::getDelFlag)); + if (tenantId != null && MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) { + kindQw.eq(MesXslMixerMaterialKindCfg::getTenantId, tenantId); + } + if (oConvertUtils.isNotEmpty(excludeId)) { + kindQw.ne(MesXslMixerMaterialKindCfg::getId, excludeId); + } + if (count(kindQw) > 0) { + throw new JeecgBootException("种类键值已存在:" + line.getKindKey()); + } + + LambdaQueryWrapper refQw = new LambdaQueryWrapper<>(); + refQw.eq(MesXslMixerMaterialKindCfg::getCategoryRefId, line.getCategoryRefId().trim()); + refQw.and(q -> q.eq(MesXslMixerMaterialKindCfg::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesXslMixerMaterialKindCfg::getDelFlag)); + if (tenantId != null && MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) { + refQw.eq(MesXslMixerMaterialKindCfg::getTenantId, tenantId); + } + if (oConvertUtils.isNotEmpty(excludeId)) { + refQw.ne(MesXslMixerMaterialKindCfg::getId, excludeId); + } + if (count(refQw) > 0) { + throw new JeecgBootException("对应分类已配置:" + line.getCategoryRefName()); + } + } + + private static Integer resolveTenantId(Integer tenantId) { + if (tenantId != null) { + return tenantId; + } + String ts = TenantContext.getTenant(); + if (oConvertUtils.isEmpty(ts)) { + try { + HttpServletRequest request = SpringContextUtils.getHttpServletRequest(); + if (request != null) { + ts = TokenUtils.getTenantIdByRequest(request); + } + } catch (Exception ignored) { + // ignore + } + } + if (oConvertUtils.isEmpty(ts)) { + return null; + } + try { + return Integer.parseInt(ts); + } catch (NumberFormatException e) { + return null; + } + } + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置展开与批量保存----------- +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java index f927a3d..6f55c62 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java @@ -2,14 +2,24 @@ package org.jeecg.modules.xslmes.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.baomidou.mybatisplus.extension.toolkit.Db; import jakarta.annotation.Resource; import java.io.Serializable; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.jeecg.common.constant.CommonConstant; +import org.jeecg.modules.mes.material.entity.MesMixerMaterial; +import org.jeecg.modules.mes.material.service.IMesMixerMaterialService; +import org.jeecg.modules.system.entity.SysCategory; +import org.jeecg.modules.system.service.ISysCategoryService; import org.jeecg.modules.xslmes.entity.MesXslMixingSpec; import org.jeecg.modules.xslmes.entity.MesXslMixingSpecDownStep; import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial; @@ -27,11 +37,19 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @Service +@Slf4j public class MesXslMixingSpecServiceImpl extends ServiceImpl implements IMesXslMixingSpecService { private static final String TCU_UP = "up_mixer"; private static final String TCU_DOWN = "down_mixer"; + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A49】删除混炼示方时同步删除B/F段胶密炼物料----------- + private static final String CATEGORY_MASTER_MAJOR = "XSLMES_MATERIAL_MASTER"; + private static final String CATEGORY_MASTER_MINOR_A = "XSLMES_MATERIAL_MASTER_A"; + private static final String CATEGORY_FINAL_MAJOR = "XSLMES_MATERIAL_FINAL"; + private static final String CATEGORY_FINAL_MINOR_Q = "XSLMES_MATERIAL_FINAL_Q"; + private static final Pattern GENERATED_B_RUBBER_SPEC_PATTERN = Pattern.compile("^B\\d", Pattern.CASE_INSENSITIVE); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A49】删除混炼示方时同步删除B/F段胶密炼物料----------- @Resource private MesXslMixingSpecMaterialMapper materialMapper; @@ -42,6 +60,12 @@ public class MesXslMixingSpecServiceImpl extends ServiceImpl stepList, List downStepList, List tcuList) { + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- + SavePerfTrace trace = new SavePerfTrace("新增", main); + trace.logPayloadSize(materialList, stepList, downStepList, tcuList); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表新增保存----------- normalizeMain(main); + trace.step("normalizeMain"); this.save(main); - saveChildren(main.getId(), materialList, stepList, downStepList, tcuList); + trace.step("saveMain", "mainId", main.getId()); + saveChildren(main.getId(), materialList, stepList, downStepList, tcuList, trace); + trace.finish(); //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表新增保存----------- } @@ -65,19 +96,32 @@ public class MesXslMixingSpecServiceImpl extends ServiceImpl stepList, List downStepList, List tcuList) { + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- + SavePerfTrace trace = new SavePerfTrace("编辑", main); + trace.logPayloadSize(materialList, stepList, downStepList, tcuList); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表编辑保存----------- normalizeMain(main); + trace.step("normalizeMain"); this.updateById(main); - clearChildren(main.getId()); - saveChildren(main.getId(), materialList, stepList, downStepList, tcuList); + trace.step("updateMain"); + clearChildren(main.getId(), trace); + saveChildren(main.getId(), materialList, stepList, downStepList, tcuList, trace); + trace.finish(); //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表编辑保存----------- } @Override @Transactional(rollbackFor = Exception.class) public void delMain(String id) { + MesXslMixingSpec main = this.getById(id); clearChildren(id); this.removeById(id); + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A49】删除混炼示方时同步删除B/F段胶密炼物料----------- + if (main != null) { + syncDeleteGeneratedRubberMixerMaterial(main.getSpecName()); + } + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A49】删除混炼示方时同步删除B/F段胶密炼物料----------- } @Override @@ -203,10 +247,26 @@ public class MesXslMixingSpecServiceImpl extends ServiceImpl().eq(MesXslMixingSpecMaterial::getMixingSpecId, mainId)); + if (trace != null) { + trace.step("deleteMaterialChildren"); + } stepMapper.delete(new LambdaQueryWrapper().eq(MesXslMixingSpecStep::getMixingSpecId, mainId)); + if (trace != null) { + trace.step("deleteStepChildren"); + } downStepMapper.delete(new LambdaQueryWrapper().eq(MesXslMixingSpecDownStep::getMixingSpecId, mainId)); + if (trace != null) { + trace.step("deleteDownStepChildren"); + } tcuMapper.delete(new LambdaQueryWrapper().eq(MesXslMixingSpecTcu::getMixingSpecId, mainId)); + if (trace != null) { + trace.step("deleteTcuChildren"); + } } private void saveChildren( @@ -215,54 +275,142 @@ public class MesXslMixingSpecServiceImpl extends ServiceImpl stepList, List downStepList, List tcuList) { + saveChildren(mainId, materialList, stepList, downStepList, tcuList, null); + } + + private void saveChildren( + String mainId, + List materialList, + List stepList, + List downStepList, + List tcuList, + SavePerfTrace trace) { + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方子表批量插入避免保存超时----------- Date now = new Date(); + saveMaterialChildren(mainId, materialList, now, trace); + saveStepChildren(mainId, stepList, now, trace); + saveDownStepChildren(mainId, downStepList, now, trace); + saveTcuChildren(mainId, tcuList, now, trace); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方子表批量插入避免保存超时----------- + } + + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方子表批量插入避免保存超时----------- + private void saveMaterialChildren(String mainId, List materialList, Date now) { + saveMaterialChildren(mainId, materialList, now, null); + } + + private void saveMaterialChildren(String mainId, List materialList, Date now, SavePerfTrace trace) { + if (CollectionUtils.isEmpty(materialList)) { + return; + } + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计----------- + fillMaterialAccumWeight(materialList); + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计----------- + if (trace != null) { + trace.step("fillMaterialAccumWeight", "rows", countRows(materialList)); + } + List rows = new ArrayList<>(); int sort = 0; - if (!CollectionUtils.isEmpty(materialList)) { - for (MesXslMixingSpecMaterial row : materialList) { - if (row == null) { - continue; - } - row.setId(null); - row.setMixingSpecId(mainId); - row.setSortNo(sort++); - if (row.getCreateTime() == null) { - row.setCreateTime(now); - } - materialMapper.insert(row); + for (MesXslMixingSpecMaterial row : materialList) { + if (row == null) { + continue; + } + row.setId(null); + row.setMixingSpecId(mainId); + row.setSortNo(sort++); + if (row.getCreateTime() == null) { + row.setCreateTime(now); + } + rows.add(row); + } + if (trace != null) { + trace.step("buildMaterialRows", "rows", rows.size()); + } + if (!rows.isEmpty()) { + Db.saveBatch(rows); + if (trace != null) { + trace.step("batchInsertMaterial", "rows", rows.size()); } } - sort = 0; - if (!CollectionUtils.isEmpty(stepList)) { - for (MesXslMixingSpecStep row : stepList) { - if (row == null) { - continue; - } - row.setId(null); - row.setMixingSpecId(mainId); - row.setSortNo(sort++); - if (row.getCreateTime() == null) { - row.setCreateTime(now); - } - stepMapper.insert(row); + } + + private void saveStepChildren(String mainId, List stepList, Date now) { + saveStepChildren(mainId, stepList, now, null); + } + + private void saveStepChildren(String mainId, List stepList, Date now, SavePerfTrace trace) { + if (CollectionUtils.isEmpty(stepList)) { + return; + } + List rows = new ArrayList<>(); + int sort = 0; + for (MesXslMixingSpecStep row : stepList) { + if (row == null) { + continue; + } + row.setId(null); + row.setMixingSpecId(mainId); + row.setSortNo(sort++); + if (row.getCreateTime() == null) { + row.setCreateTime(now); + } + rows.add(row); + } + if (trace != null) { + trace.step("buildStepRows", "rows", rows.size()); + } + if (!rows.isEmpty()) { + Db.saveBatch(rows); + if (trace != null) { + trace.step("batchInsertStep", "rows", rows.size()); } } - sort = 0; - if (!CollectionUtils.isEmpty(downStepList)) { - for (MesXslMixingSpecDownStep row : downStepList) { - if (row == null) { - continue; - } - row.setId(null); - row.setMixingSpecId(mainId); - row.setSortNo(sort++); - if (row.getCreateTime() == null) { - row.setCreateTime(now); - } - downStepMapper.insert(row); + } + + private void saveDownStepChildren(String mainId, List downStepList, Date now) { + saveDownStepChildren(mainId, downStepList, now, null); + } + + private void saveDownStepChildren(String mainId, List downStepList, Date now, SavePerfTrace trace) { + if (CollectionUtils.isEmpty(downStepList)) { + return; + } + List rows = new ArrayList<>(); + int sort = 0; + for (MesXslMixingSpecDownStep row : downStepList) { + if (row == null) { + continue; + } + row.setId(null); + row.setMixingSpecId(mainId); + row.setSortNo(sort++); + if (row.getCreateTime() == null) { + row.setCreateTime(now); + } + rows.add(row); + } + if (trace != null) { + trace.step("buildDownStepRows", "rows", rows.size()); + } + if (!rows.isEmpty()) { + Db.saveBatch(rows); + if (trace != null) { + trace.step("batchInsertDownStep", "rows", rows.size()); } } + } + + private void saveTcuChildren(String mainId, List tcuList, Date now) { + saveTcuChildren(mainId, tcuList, now, null); + } + + private void saveTcuChildren(String mainId, List tcuList, Date now, SavePerfTrace trace) { List tcuRows = fillDefaultTcuRows(tcuList); - sort = 0; + if (trace != null) { + trace.step("fillDefaultTcuRows", "rows", tcuRows.size()); + } + List rows = new ArrayList<>(); + int sort = 0; for (MesXslMixingSpecTcu row : tcuRows) { row.setId(null); row.setMixingSpecId(mainId); @@ -273,9 +421,139 @@ public class MesXslMixingSpecServiceImpl extends ServiceImpl rows) { + return rows == null ? 0 : rows.size(); + } + + /** 混炼示方保存性能追踪(临时诊断日志,定位慢步骤) */ + private static final class SavePerfTrace { + private final String action; + private final String mainId; + private final String specName; + private final long startMs = System.currentTimeMillis(); + private long lastMs = startMs; + private final StringBuilder summary = new StringBuilder(); + + private SavePerfTrace(String action, MesXslMixingSpec main) { + this.action = action; + this.mainId = main != null ? main.getId() : null; + this.specName = main != null ? main.getSpecName() : null; + summary.append("action=").append(action); + if (StringUtils.isNotBlank(mainId)) { + summary.append(", mainId=").append(mainId); + } + if (StringUtils.isNotBlank(specName)) { + summary.append(", specName=").append(specName); + } + } + + private void logPayloadSize( + List materialList, + List stepList, + List downStepList, + List tcuList) { + log.info( + "[混炼示方保存性能] 开始{} specName={}, mainId={}, payload=[material={}, step={}, downStep={}, tcu={}]", + action, + specName, + mainId, + countRows(materialList), + countRows(stepList), + countRows(downStepList), + countRows(tcuList)); + } + + private void step(String stepName, Object... kvPairs) { + long now = System.currentTimeMillis(); + long stepMs = now - lastMs; + long totalMs = now - startMs; + summary.append(" | ").append(stepName).append('=').append(stepMs).append("ms"); + if (kvPairs != null && kvPairs.length > 0) { + summary.append('('); + for (int i = 0; i < kvPairs.length; i += 2) { + if (i > 0) { + summary.append(", "); + } + summary.append(kvPairs[i]).append('=').append(kvPairs[i + 1]); + } + summary.append(')'); + } + log.info("[混炼示方保存性能] {} 步骤={} 本步耗时={}ms 累计={}ms", action, stepName, stepMs, totalMs); + lastMs = now; + } + + private void finish() { + log.info("[混炼示方保存性能] 完成{} 总耗时={}ms | {}", action, System.currentTimeMillis() - startMs, summary); + } + } + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志----------- + + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计----------- + /** 按种类连续分组,累计写入每组最后一行 */ + private void fillMaterialAccumWeight(List materials) { + if (CollectionUtils.isEmpty(materials)) { + return; + } + int index = 0; + while (index < materials.size()) { + MesXslMixingSpecMaterial current = materials.get(index); + if (!isMaterialDataRow(current)) { + current.setAccumWeight(null); + index++; + continue; + } + String kind = normalizeMaterialKind(current); + int groupEnd = index; + BigDecimal sum = BigDecimal.ZERO; + while (groupEnd < materials.size()) { + MesXslMixingSpecMaterial row = materials.get(groupEnd); + if (!isMaterialDataRow(row) || !kind.equals(normalizeMaterialKind(row))) { + break; + } + if (row.getUnitWeight() != null) { + sum = sum.add(row.getUnitWeight()); + } + groupEnd++; + } + for (int rowIndex = index; rowIndex < groupEnd; rowIndex++) { + if (rowIndex == groupEnd - 1) { + materials.get(rowIndex).setAccumWeight(sum.compareTo(BigDecimal.ZERO) != 0 ? sum : null); + } else { + materials.get(rowIndex).setAccumWeight(null); + } + } + index = groupEnd; + } + } + + private boolean isMaterialDataRow(MesXslMixingSpecMaterial row) { + if (row == null) { + return false; + } + return StringUtils.isNotBlank(row.getMixerMaterialName()) + || row.getUnitWeight() != null + || StringUtils.isNotBlank(row.getMaterialKind()); + } + + private String normalizeMaterialKind(MesXslMixingSpecMaterial row) { + return StringUtils.isNotBlank(row.getMaterialKind()) ? row.getMaterialKind().trim() : ""; + } + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计----------- private List queryMaterialByMainId(String mainId) { return materialMapper.selectList( @@ -336,4 +614,112 @@ public class MesXslMixingSpecServiceImpl extends ServiceImpl().eq(MesXslMixingSpec::getSpecName, specCode)); + if (remainingSpecCount > 0) { + log.debug("[混炼示方删除] 示方编号 {} 仍有 {} 条混炼示方,跳过密炼物料同步删除", specCode, remainingSpecCount); + return; + } + long referencedCount = materialMapper.selectCount( + new LambdaQueryWrapper().eq(MesXslMixingSpecMaterial::getMixerMaterialName, specCode)); + if (referencedCount > 0) { + log.info( + "[混炼示方删除] 示方编号 {} 仍被 {} 条混炼示方明细引用,跳过密炼物料同步删除", + specCode, + referencedCount); + return; + } + MesMixerMaterial material = findMixerMaterialByCodeOrName(specCode); + if (material == null) { + log.debug("[混炼示方删除] 未找到示方编号 {} 对应密炼物料,跳过同步删除", specCode); + return; + } + Map categoryIdCache = new HashMap<>(); + if (!isGeneratedRubberMixerMaterial(material, isFinalStage, categoryIdCache)) { + log.info( + "[混炼示方删除] 密炼物料 id={}, code={} 分类非生成示方自动同步类型,跳过删除", + material.getId(), + specCode); + return; + } + mesMixerMaterialService.removeById(material.getId()); + log.info("[混炼示方删除] 同步删除密炼物料 id={}, code={}", material.getId(), specCode); + } + + /** 判断是否为生成混炼示方时自动同步的 B/F 段胶示方编号;true=F段,false=B段,null=非自动生成胶料编号 */ + private Boolean resolveGeneratedRubberSegment(String specCode) { + if (StringUtils.isBlank(specCode)) { + return null; + } + String normalized = specCode.trim(); + if (normalized.toUpperCase().startsWith("F")) { + return true; + } + if (GENERATED_B_RUBBER_SPEC_PATTERN.matcher(normalized).find()) { + return false; + } + return null; + } + + private MesMixerMaterial findMixerMaterialByCodeOrName(String specCode) { + MesMixerMaterial byCode = mesMixerMaterialService.getOne( + new LambdaQueryWrapper() + .eq(MesMixerMaterial::getMaterialCode, specCode) + .and(w -> w.eq(MesMixerMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMixerMaterial::getDelFlag)) + .last("limit 1")); + if (byCode != null) { + return byCode; + } + return mesMixerMaterialService.getOne( + new LambdaQueryWrapper() + .eq(MesMixerMaterial::getMaterialName, specCode) + .and(w -> w.eq(MesMixerMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMixerMaterial::getDelFlag)) + .last("limit 1")); + } + + private boolean isGeneratedRubberMixerMaterial( + MesMixerMaterial material, boolean isFinalStage, Map categoryIdCache) { + if (material == null) { + return false; + } + String majorCode = isFinalStage ? CATEGORY_FINAL_MAJOR : CATEGORY_MASTER_MAJOR; + String minorCode = isFinalStage ? CATEGORY_FINAL_MINOR_Q : CATEGORY_MASTER_MINOR_A; + String expectedMajorId = resolveCategoryIdByCode(majorCode, categoryIdCache); + String expectedMinorId = resolveCategoryIdByCode(minorCode, categoryIdCache); + if (StringUtils.isBlank(expectedMajorId) || StringUtils.isBlank(expectedMinorId)) { + return false; + } + return expectedMajorId.equals(material.getMajorCategoryId()) && expectedMinorId.equals(material.getMinorCategoryId()); + } + + private String resolveCategoryIdByCode(String categoryCode, Map cache) { + if (StringUtils.isBlank(categoryCode)) { + return null; + } + if (cache != null && cache.containsKey(categoryCode)) { + return cache.get(categoryCode); + } + SysCategory category = sysCategoryService.getOne( + new LambdaQueryWrapper().eq(SysCategory::getCode, categoryCode.trim()).last("limit 1")); + String categoryId = category != null ? category.getId() : null; + if (cache != null) { + cache.put(categoryCode, categoryId); + } + return categoryId; + } + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A49】删除混炼示方时同步删除B/F段胶密炼物料----------- } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java index 869b23c..9e48a55 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java @@ -29,8 +29,8 @@ import java.util.stream.Collectors; @Service public class SysCategoryServiceImpl extends ServiceImpl implements ISysCategoryService { - /** 原辅材料分类编码(其子类可标记为胶料) */ - private static final String MATERIAL_RAW_AUX_CODE = "XSLMES_MATERIAL_RAW_AUX"; + /** MES 物料大类编码前缀(其直接子类为物料小类,可标记胶料) */ + private static final String MATERIAL_MAJOR_CODE_PREFIX = "XSLMES_MATERIAL_"; @Override public void addSysCategory(SysCategory sysCategory) { @@ -103,9 +103,9 @@ public class SysCategoryServiceImpl extends ServiceImpl queryListByCode(String pcode) throws JeecgBootException{ diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_102__mes_xsl_mixer_material_kind_cfg.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_102__mes_xsl_mixer_material_kind_cfg.sql new file mode 100644 index 0000000..095ec4e --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_102__mes_xsl_mixer_material_kind_cfg.sql @@ -0,0 +1,91 @@ +-- 密炼物料种类配置:建表 + 菜单(挂 MES技术管理)+ admin 授权 +SET NAMES utf8mb4; + +CREATE TABLE IF NOT EXISTS `mes_xsl_mixer_material_kind_cfg` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `kind_key` varchar(100) NOT NULL COMMENT '种类键值', + `kind_name` varchar(200) NOT NULL COMMENT '种类名称', + `source_type` varchar(20) NOT NULL COMMENT '数据源类型:dict数据字典/category分类字典', + `source_root_code` varchar(100) DEFAULT NULL COMMENT '根字典编码或分类pcode', + `source_root_name` varchar(200) DEFAULT NULL COMMENT '根名称冗余', + `category_ref_id` varchar(32) DEFAULT NULL COMMENT '对应分类/字典项ID', + `category_ref_code` varchar(100) DEFAULT NULL COMMENT '对应分类编码/字典项值', + `category_ref_name` varchar(200) DEFAULT NULL COMMENT '对应分类名称冗余', + `tenant_id` int DEFAULT NULL COMMENT '租户ID', + `priority` int DEFAULT '0' COMMENT '优先级(数字越小越优先)', + `sys_org_code` varchar(64) DEFAULT NULL COMMENT '所属部门', + `create_by` varchar(50) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(50) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `del_flag` int NOT NULL DEFAULT '0' COMMENT '逻辑删除(0正常 1已删除)', + PRIMARY KEY (`id`), + KEY `idx_mxmmkc_tenant_priority` (`tenant_id`, `priority`), + KEY `idx_mxmmkc_source_root` (`source_type`, `source_root_code`), + KEY `idx_mxmmkc_category_ref` (`category_ref_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES密炼物料种类配置'; + +UPDATE `sys_permission` +SET `is_leaf` = 0, `update_time` = NOW() +WHERE `id` = '1900000000000000810' AND `is_leaf` = 1; + +INSERT INTO `sys_permission` ( + `id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, + `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, + `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, + `del_flag`, `rule_flag`, `status`, `internal_or_external` +) +SELECT + '177925970995550', '1900000000000000810', '密炼物料种类配置', '/xslmes/mesXslMixerMaterialKindCfg', + 'xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfgList', 1, 'MesXslMixerMaterialKindCfgList', NULL, + 1, NULL, '0', 3.00, 0, 'ant-design:tags-outlined', 0, 1, + 0, 0, 'MES密炼物料种类配置', 'admin', NOW(), 'admin', NOW(), + 0, 0, '1', 0 +FROM DUAL +WHERE NOT EXISTS ( + SELECT 1 FROM `sys_permission` + WHERE `id` = '177925970995550' + OR (`del_flag` = 0 AND `menu_type` = 1 AND `name` = '密炼物料种类配置' AND `parent_id` = '1900000000000000810') +); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995551', '177925970995550', '新增', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:add', '1', 1.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995551'); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995552', '177925970995550', '编辑', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:edit', '1', 2.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995552'); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995553', '177925970995550', '删除', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:delete', '1', 3.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995553'); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995554', '177925970995550', '批量删除', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:deleteBatch', '1', 4.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995554'); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995555', '177925970995550', '导出', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:exportXls', '1', 5.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995555'); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995556', '177925970995550', '导入', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:importExcel', '1', 6.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995556'); + +INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`) +SELECT REPLACE(UUID(), '-', ''), r.id, p.id, NULL, NOW(), '127.0.0.1' +FROM `sys_role` r +CROSS JOIN `sys_permission` p +WHERE r.`role_code` = 'admin' + AND p.`id` IN ( + '177925970995550', + '177925970995551', + '177925970995552', + '177925970995553', + '177925970995554', + '177925970995555', + '177925970995556' + ) + AND NOT EXISTS ( + SELECT 1 FROM `sys_role_permission` rp WHERE rp.`role_id` = r.`id` AND rp.`permission_id` = p.`id` + ); diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_103__mes_xsl_mixer_material_kind_cfg_menu_fix.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_103__mes_xsl_mixer_material_kind_cfg_menu_fix.sql new file mode 100644 index 0000000..a730d7e --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_103__mes_xsl_mixer_material_kind_cfg_menu_fix.sql @@ -0,0 +1,67 @@ +-- 密炼物料种类配置:菜单 ID 与配合示方(177925970995530)冲突,补插正确菜单 +SET NAMES utf8mb4; + +UPDATE `sys_permission` +SET `is_leaf` = 0, `update_time` = NOW() +WHERE `id` = '1900000000000000810'; + +INSERT INTO `sys_permission` ( + `id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, + `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, + `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, + `del_flag`, `rule_flag`, `status`, `internal_or_external` +) +SELECT + '177925970995550', '1900000000000000810', '密炼物料种类配置', '/xslmes/mesXslMixerMaterialKindCfg', + 'xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfgList', 1, 'MesXslMixerMaterialKindCfgList', NULL, + 1, NULL, '0', 3.00, 0, 'ant-design:tags-outlined', 0, 1, + 0, 0, 'MES密炼物料种类配置', 'admin', NOW(), 'admin', NOW(), + 0, 0, '1', 0 +FROM DUAL +WHERE NOT EXISTS ( + SELECT 1 FROM `sys_permission` + WHERE `id` = '177925970995550' + OR (`del_flag` = 0 AND `menu_type` = 1 AND `name` = '密炼物料种类配置' AND `parent_id` = '1900000000000000810') +); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995551', '177925970995550', '新增', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:add', '1', 1.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995551'); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995552', '177925970995550', '编辑', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:edit', '1', 2.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995552'); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995553', '177925970995550', '删除', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:delete', '1', 3.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995553'); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995554', '177925970995550', '批量删除', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:deleteBatch', '1', 4.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995554'); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995555', '177925970995550', '导出', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:exportXls', '1', 5.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995555'); + +INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`) +SELECT '177925970995556', '177925970995550', '导入', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:importExcel', '1', 6.00, 0, 1, 0, '1', 0, 'admin', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995556'); + +INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`) +SELECT REPLACE(UUID(), '-', ''), r.id, p.id, NULL, NOW(), '127.0.0.1' +FROM `sys_role` r +CROSS JOIN `sys_permission` p +WHERE r.`role_code` = 'admin' + AND p.`id` IN ( + '177925970995550', + '177925970995551', + '177925970995552', + '177925970995553', + '177925970995554', + '177925970995555', + '177925970995556' + ) + AND NOT EXISTS ( + SELECT 1 FROM `sys_role_permission` rp WHERE rp.`role_id` = r.`id` AND rp.`permission_id` = p.`id` + ); diff --git a/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue b/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue index 9750f98..8d167a0 100644 --- a/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue +++ b/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue @@ -13,7 +13,8 @@ import { loadTreeData } from '/@/views/system/category/category.api'; import { MATERIAL_RAW_AUX_CODE, materialRawAuxCategoryId, - isMaterialRawAuxSubCategory, + ensureMaterialCategoryContext, + isMaterialMinorCategory, toIsRubberFlag, fromIsRubberFlag, } from '/@/views/system/category/category.constants'; @@ -48,7 +49,7 @@ const schemas: FormSchema[] = [ defaultValue: false, renderComponentContent: '胶料', colProps: { span: 24 }, - ifShow: ({ values }) => isMaterialRawAuxSubCategory(values.pid), + ifShow: ({ values }) => isMaterialMinorCategory(values.pid), }, ]; @@ -95,7 +96,7 @@ async function ensureMaterialRawAuxCategoryId() { function normalizeSubmitValues(values: Recordable) { const payload = { ...values }; - payload.isRubber = isMaterialRawAuxSubCategory(payload.pid) ? toIsRubberFlag(payload.isRubber) : '0'; + payload.isRubber = isMaterialMinorCategory(payload.pid) ? toIsRubberFlag(payload.isRubber) : '0'; return payload; } @@ -104,6 +105,7 @@ const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data setModalProps({ confirmLoading: false }); isUpdate.value = !!data?.isUpdate; await ensureMaterialRawAuxCategoryId(); + await ensureMaterialCategoryContext(); const tree = await buildPidTree(); if (!tree.length) { createMessage.warning('未加载到物料分类树,请确认分类字典根编码 XSLMES_MATERIAL 已存在'); diff --git a/jeecgboot-vue3/src/views/system/category/category.constants.ts b/jeecgboot-vue3/src/views/system/category/category.constants.ts index 011798f..40aca17 100644 --- a/jeecgboot-vue3/src/views/system/category/category.constants.ts +++ b/jeecgboot-vue3/src/views/system/category/category.constants.ts @@ -1,16 +1,78 @@ import { ref } from 'vue'; +import { defHttp } from '/@/utils/http/axios'; +import { getChildListBatch, loadTreeData } from './category.api'; -/** MES 物料分类 - 原辅材料编码 */ +/** MES 物料分类根编码 */ +export const MATERIAL_ROOT_CODE = 'XSLMES_MATERIAL'; + +/** MES 物料分类 - 原辅材料编码(兼容旧逻辑) */ export const MATERIAL_RAW_AUX_CODE = 'XSLMES_MATERIAL_RAW_AUX'; -/** 原辅材料分类节点 ID(运行时加载) */ +/** 原辅材料分类节点 ID(运行时加载,兼容旧逻辑) */ export const materialRawAuxCategoryId = ref(''); -/** 是否为原辅材料的直接子类 */ +/** MES 物料分类根节点 ID(运行时加载) */ +export const materialRootCategoryId = ref(''); + +/** MES 物料大类节点 ID 集合(运行时加载) */ +export const materialMajorCategoryIds = ref>(new Set()); + +let materialCategoryContextLoading: Promise | null = null; + +/** 加载 MES 物料分类上下文(根节点 + 大类 ID) */ +export async function ensureMaterialCategoryContext(force = false) { + if (!force && materialRootCategoryId.value && materialMajorCategoryIds.value.size > 0) { + return; + } + if (materialCategoryContextLoading) { + await materialCategoryContextLoading; + return; + } + materialCategoryContextLoading = (async () => { + const rootRes = await defHttp.get( + { url: '/sys/category/loadOne', params: { field: 'code', val: MATERIAL_ROOT_CODE } }, + { isTransformResponse: false }, + ); + if (rootRes?.success && rootRes?.result?.id) { + materialRootCategoryId.value = String(rootRes.result.id); + } + const auxRes = await defHttp.get( + { url: '/sys/category/loadOne', params: { field: 'code', val: MATERIAL_RAW_AUX_CODE } }, + { isTransformResponse: false }, + ); + if (auxRes?.success && auxRes?.result?.id) { + materialRawAuxCategoryId.value = String(auxRes.result.id); + } + const majors = await loadTreeData({ async: false, pcode: MATERIAL_ROOT_CODE }); + const majorIds = new Set(); + (Array.isArray(majors) ? majors : []).forEach((node) => { + const nodeKey = node?.key ?? node?.value ?? node?.id; + if (nodeKey != null) { + majorIds.add(String(nodeKey)); + } + }); + materialMajorCategoryIds.value = majorIds; + })(); + try { + await materialCategoryContextLoading; + } finally { + materialCategoryContextLoading = null; + } +} + +/** 是否为原辅材料的直接子类(兼容旧逻辑) */ export function isMaterialRawAuxSubCategory(pid?: string) { return !!materialRawAuxCategoryId.value && pid === materialRawAuxCategoryId.value; } +/** 是否为 MES 物料小类(父节点为物料大类) */ +export function isMaterialMinorCategory(pid?: string) { + if (!pid) { + return false; + } + return materialMajorCategoryIds.value.has(String(pid)); +} + /** 表单 Checkbox 布尔值 -> 数据库存储值 */ export function toIsRubberFlag(value: unknown) { return value === true || value === '1' ? '1' : '0'; @@ -20,3 +82,206 @@ export function toIsRubberFlag(value: unknown) { export function fromIsRubberFlag(value: unknown) { return value === '1' || value === 1 || value === true; } + +//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】统一加载MES物料分类树(大类+小类)----------- +export interface MesMaterialCategoryMinorItem { + id: string; + name: string; + majorId: string; + majorName: string; + label: string; +} + +export interface MesMaterialCategoryMajorItem { + id: string; + name: string; + minors: MesMaterialCategoryMinorItem[]; +} + +export interface MesMaterialCategoryTreeLoadResult { + majors: MesMaterialCategoryMajorItem[]; + minors: MesMaterialCategoryMinorItem[]; + treeNodes: Recordable[]; +} + +function normalizeCategoryNodeKey(node: Recordable): string { + const key = node?.key ?? node?.value ?? node?.id; + return key != null && String(key) !== '' ? String(key) : ''; +} + +function normalizeCategoryNodeTitle(node: Recordable): string { + return String(node?.title ?? node?.name ?? ''); +} + +function normalizeTreeSelectNodes(nodes: unknown): Recordable[] { + if (Array.isArray(nodes)) { + return nodes as Recordable[]; + } + if (nodes && typeof nodes === 'object') { + const payload = nodes as Recordable; + if (Array.isArray(payload.result)) { + return payload.result; + } + if (Array.isArray(payload.records)) { + return payload.records; + } + } + return []; +} + +/** 加载 MES 物料分类树:根下物料大类 + 各物料小类(供密炼物料/混炼示方选料复用) */ +export async function loadMesMaterialCategoryTreeData(): Promise { + // 优先 loadTreeRoot(与密炼物料列表页一致,已验证可用) + try { + const treeRes = await loadTreeData({ async: false, pcode: MATERIAL_ROOT_CODE }); + const treeResult = buildMesMaterialCategoryTreeFromTreeSelect(normalizeTreeSelectNodes(treeRes)); + if (treeResult.minors.length) { + if (!materialRootCategoryId.value) { + await ensureMaterialCategoryContext(); + } + return treeResult; + } + } catch { + // 继续走 batch 兜底 + } + + let rootId = materialRootCategoryId.value; + if (!rootId) { + try { + const root = await defHttp.get({ + url: '/sys/category/loadOne', + params: { field: 'code', val: MATERIAL_ROOT_CODE }, + }); + if (root?.id) { + rootId = String(root.id); + materialRootCategoryId.value = rootId; + } + } catch { + rootId = ''; + } + } + if (!rootId) { + return { majors: [], minors: [], treeNodes: [] }; + } + + let majorRecords: Recordable[] = []; + let minorRecords: Recordable[] = []; + try { + const majorBatch = await getChildListBatch({ parentIds: rootId }); + if (majorBatch?.success === false) { + return { majors: [], minors: [], treeNodes: [] }; + } + majorRecords = (majorBatch?.result?.records || majorBatch?.records || []) as Recordable[]; + if (majorRecords.length) { + const majorIds = majorRecords.map((item) => String(item.id)).filter(Boolean).join(','); + if (majorIds) { + const minorBatch = await getChildListBatch({ parentIds: majorIds }); + if (minorBatch?.success !== false) { + minorRecords = (minorBatch?.result?.records || minorBatch?.records || []) as Recordable[]; + } + } + } + } catch { + return { majors: [], minors: [], treeNodes: [] }; + } + + const result = buildMesMaterialCategoryTreeFromRecords(majorRecords, minorRecords); + materialMajorCategoryIds.value = new Set(result.majors.map((item) => item.id)); + return result; +} + +function buildMesMaterialCategoryTreeFromRecords(majorRecords: Recordable[], minorRecords: Recordable[]) { + const majorMap = new Map(); + majorRecords.forEach((record) => { + const majorId = normalizeCategoryNodeKey(record); + if (!majorId) { + return; + } + majorMap.set(majorId, { + id: majorId, + name: normalizeCategoryNodeTitle(record), + minors: [], + }); + }); + + minorRecords.forEach((record) => { + const majorId = record?.pid != null ? String(record.pid) : ''; + const minorId = normalizeCategoryNodeKey(record); + const major = majorMap.get(majorId); + if (!major || !minorId) { + return; + } + major.minors.push({ + id: minorId, + name: normalizeCategoryNodeTitle(record), + majorId: major.id, + majorName: major.name, + label: major.name && normalizeCategoryNodeTitle(record) + ? `${major.name} / ${normalizeCategoryNodeTitle(record)}` + : normalizeCategoryNodeTitle(record) || major.name, + }); + }); + + const majors: MesMaterialCategoryMajorItem[] = []; + const minors: MesMaterialCategoryMinorItem[] = []; + const treeNodes: Recordable[] = []; + + majorMap.forEach((major) => { + if (!major.minors.length) { + return; + } + majors.push({ id: major.id, name: major.name, minors: major.minors }); + minors.push(...major.minors); + treeNodes.push({ + key: major.id, + title: major.name, + children: major.minors.map((minor) => ({ key: minor.id, title: minor.name })), + }); + }); + + return { majors, minors, treeNodes }; +} + +function buildMesMaterialCategoryTreeFromTreeSelect(majorRaw: Recordable[]) { + const majors: MesMaterialCategoryMajorItem[] = []; + const minors: MesMaterialCategoryMinorItem[] = []; + const treeNodes: Recordable[] = []; + + majorRaw.forEach((major) => { + const majorId = normalizeCategoryNodeKey(major); + const majorName = normalizeCategoryNodeTitle(major); + if (!majorId) { + return; + } + const majorMinors: MesMaterialCategoryMinorItem[] = []; + (Array.isArray(major.children) ? major.children : []).forEach((child) => { + const minorId = normalizeCategoryNodeKey(child); + const minorName = normalizeCategoryNodeTitle(child); + if (!minorId) { + return; + } + const item: MesMaterialCategoryMinorItem = { + id: minorId, + name: minorName, + majorId, + majorName, + label: majorName && minorName ? `${majorName} / ${minorName}` : minorName || majorName, + }; + majorMinors.push(item); + minors.push(item); + }); + if (!majorMinors.length) { + return; + } + majors.push({ id: majorId, name: majorName, minors: majorMinors }); + treeNodes.push({ + key: majorId, + title: majorName, + children: majorMinors.map((minor) => ({ key: minor.id, title: minor.name })), + }); + }); + + materialMajorCategoryIds.value = new Set(majors.map((item) => item.id)); + return { majors, minors, treeNodes }; +} +//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】统一加载MES物料分类树(大类+小类)----------- diff --git a/jeecgboot-vue3/src/views/system/category/category.data.ts b/jeecgboot-vue3/src/views/system/category/category.data.ts index 8adedf2..a57e10c 100644 --- a/jeecgboot-vue3/src/views/system/category/category.data.ts +++ b/jeecgboot-vue3/src/views/system/category/category.data.ts @@ -1,6 +1,6 @@ import { BasicColumn } from '/@/components/Table'; import { FormSchema } from '/@/components/Table'; -import { isMaterialRawAuxSubCategory } from './category.constants'; +import { isMaterialMinorCategory } from './category.constants'; export const columns: BasicColumn[] = [ { @@ -81,6 +81,6 @@ export const formSchema: FormSchema[] = [ defaultValue: false, renderComponentContent: '胶料', colProps: { span: 24 }, - show: ({ values }) => isMaterialRawAuxSubCategory(values.pid), + show: ({ values }) => isMaterialMinorCategory(values.pid), }, ]; diff --git a/jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue b/jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue index a59b3e2..09cec24 100644 --- a/jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue +++ b/jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue @@ -13,7 +13,8 @@ import { MATERIAL_RAW_AUX_CODE, materialRawAuxCategoryId, - isMaterialRawAuxSubCategory, + ensureMaterialCategoryContext, + isMaterialMinorCategory, toIsRubberFlag, fromIsRubberFlag, } from '../category.constants'; @@ -40,7 +41,7 @@ function normalizeSubmitValues(values: Recordable) { const payload = { ...values }; - payload.isRubber = isMaterialRawAuxSubCategory(payload.pid) ? toIsRubberFlag(payload.isRubber) : '0'; + payload.isRubber = isMaterialMinorCategory(payload.pid) ? toIsRubberFlag(payload.isRubber) : '0'; return payload; } //表单配置 @@ -64,6 +65,7 @@ setModalProps({ confirmLoading: false, minHeight: 80 }); isUpdate.value = !!data?.isUpdate; await ensureMaterialRawAuxCategoryId(); + await ensureMaterialCategoryContext(); // 代码逻辑说明: 分类字典data.record为空报错------------ isSubAdd.value = !data?.isUpdate && data.record && data.record.id; if (data?.record) { diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue index fe34ebc..42dfb34 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue @@ -23,6 +23,7 @@ columns: [ { title: '设备名称', dataIndex: 'equipmentName', width: 160 }, { title: '设备编号', dataIndex: 'equipmentCode', width: 140 }, + { title: '有效体积', dataIndex: 'effectiveVolume', width: 100 }, { title: '设备类别', dataIndex: 'equipmentCategoryName', width: 120 }, { title: '设备类型', dataIndex: 'equipmentTypeName', width: 120 }, ], diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerSelectModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerSelectModal.vue index 023e99b..59a23de 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerSelectModal.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerSelectModal.vue @@ -79,7 +79,7 @@ } } if (!row?.id) { - emit('select', { equipmentLedgerId: '', equipmentName: '', equipmentCode: '' }); + emit('select', { equipmentLedgerId: '', equipmentName: '', equipmentCode: '', effectiveVolume: '' }); closeModal(); return; } @@ -87,6 +87,7 @@ equipmentLedgerId: row.id, equipmentName: row.equipmentName || '', equipmentCode: row.equipmentCode || '', + effectiveVolume: row.effectiveVolume || '', }); closeModal(); } diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts index 0c034b7..bfa34cf 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts +++ b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts @@ -47,5 +47,8 @@ export const saveOrUpdate = (params, isUpdate) => defHttp.post({ url: isUpdate ? //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方----------- export const buildMixingGeneratePreview = (params) => defHttp.get({ url: Api.buildMixingGeneratePreview, params }, { successMessageMode: 'none' }); -export const generateMixingSpec = (params) => defHttp.post({ url: Api.generateMixingSpec, params }); +//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】批量生成混炼示方延长超时避免误报失败----------- +export const generateMixingSpec = (params) => + defHttp.post({ url: Api.generateMixingSpec, params, timeout: 120 * 1000 }); +//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】批量生成混炼示方延长超时避免误报失败----------- //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方----------- diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.api.ts new file mode 100644 index 0000000..26e37af --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.api.ts @@ -0,0 +1,36 @@ +import { defHttp } from '/@/utils/http/axios'; + +enum Api { + list = '/xslmes/mesXslMixerMaterialKindCfg/list', + save = '/xslmes/mesXslMixerMaterialKindCfg/add', + edit = '/xslmes/mesXslMixerMaterialKindCfg/edit', + addBatch = '/xslmes/mesXslMixerMaterialKindCfg/addBatch', + expandLines = '/xslmes/mesXslMixerMaterialKindCfg/expandLines', + deleteOne = '/xslmes/mesXslMixerMaterialKindCfg/delete', + deleteBatch = '/xslmes/mesXslMixerMaterialKindCfg/deleteBatch', + importExcel = '/xslmes/mesXslMixerMaterialKindCfg/importExcel', + exportXls = '/xslmes/mesXslMixerMaterialKindCfg/exportXls', + queryById = '/xslmes/mesXslMixerMaterialKindCfg/queryById', +} + +export const list = (params) => defHttp.get({ url: Api.list, params }); + +export const queryById = (params) => defHttp.get({ url: Api.queryById, params }); + +export const expandLines = (params) => defHttp.get({ url: Api.expandLines, params }); + +export const addBatch = (params) => defHttp.post({ url: Api.addBatch, params }, { successMessageMode: 'none' }); + +export const deleteOne = (params, handleSuccess) => + defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => handleSuccess()); + +export const batchDelete = (params, handleSuccess) => + defHttp.delete({ url: Api.deleteBatch, params }, { joinParamsToUrl: true }).then(() => handleSuccess()); + +export const saveOrUpdate = (params, isUpdate) => { + const url = isUpdate ? Api.edit : Api.save; + return defHttp.post({ url, params }, { successMessageMode: 'none' }); +}; + +export const getExportUrl = Api.exportXls; +export const getImportUrl = Api.importExcel; diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.data.ts new file mode 100644 index 0000000..d2adc00 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.data.ts @@ -0,0 +1,156 @@ +import { BasicColumn, FormSchema } from '/@/components/Table'; +import { JVxeColumn, JVxeTypes } from '/@/components/jeecg/JVxeTable/types'; +import { list as dictList } from '/@/views/system/dict/dict.api'; +import { loadTreeData } from '/@/api/common/api'; + +export const SOURCE_TYPE_OPTIONS = [ + { label: '数据字典', value: 'dict' }, + { label: '分类字典', value: 'category' }, +]; + +export const sourceTypeTextMap: Record = { + dict: '数据字典', + category: '分类字典', +}; + +export const columns: BasicColumn[] = [ + { title: '种类键值', align: 'center', dataIndex: 'kindKey', width: 120 }, + { title: '种类名称', align: 'center', dataIndex: 'kindName', width: 140 }, + { + title: '数据源', + align: 'center', + dataIndex: 'sourceType', + width: 100, + customRender: ({ text }) => sourceTypeTextMap[String(text || '')] || text || '', + }, + { title: '根名称', align: 'center', dataIndex: 'sourceRootName', width: 140 }, + { title: '对应分类', align: 'center', dataIndex: 'categoryRefName', width: 140 }, + { title: '优先级', align: 'center', dataIndex: 'priority', width: 80 }, + { title: '租户ID', align: 'center', dataIndex: 'tenantId', width: 80, defaultHidden: true }, + { title: '创建时间', align: 'center', dataIndex: 'createTime', width: 165 }, +]; + +export const searchFormSchema: FormSchema[] = [ + { label: '种类键值', field: 'kindKey', component: 'Input', colProps: { span: 6 } }, + { label: '种类名称', field: 'kindName', component: 'Input', colProps: { span: 6 } }, + { + label: '数据源', + field: 'sourceType', + component: 'Select', + componentProps: { options: SOURCE_TYPE_OPTIONS, allowClear: true }, + colProps: { span: 6 }, + }, + { label: '根编码', field: 'sourceRootCode', component: 'Input', colProps: { span: 6 } }, +]; + +export const batchFormSchema: FormSchema[] = [ + { + label: '数据源', + field: 'sourceType', + component: 'Select', + required: true, + defaultValue: 'category', + componentProps: { options: SOURCE_TYPE_OPTIONS }, + }, + { + label: '数据字典', + field: 'dictRootCode', + component: 'ApiSelect', + required: true, + ifShow: ({ values }) => values.sourceType === 'dict', + componentProps: { + api: () => dictList({ pageNo: 1, pageSize: 500 }), + resultField: 'records', + labelField: 'dictName', + valueField: 'dictCode', + showSearch: true, + placeholder: '请选择数据字典根', + }, + }, + { + label: '分类字典', + field: 'categoryRootCode', + component: 'ApiSelect', + required: true, + ifShow: ({ values }) => values.sourceType === 'category', + componentProps: { + api: loadTreeData, + params: { async: false, pcode: '0' }, + resultField: '', + labelField: 'title', + valueField: 'code', + showSearch: true, + placeholder: '请选择分类字典根', + }, + }, +]; + +export const editFormSchema: FormSchema[] = [ + { label: '', field: 'id', component: 'Input', show: false }, + { label: '', field: 'sourceType', component: 'Input', show: false }, + { label: '', field: 'sourceRootCode', component: 'Input', show: false }, + { label: '', field: 'sourceRootName', component: 'Input', show: false }, + { label: '', field: 'categoryRefId', component: 'Input', show: false }, + { label: '', field: 'categoryRefCode', component: 'Input', show: false }, + { + label: '种类键值', + field: 'kindKey', + component: 'Input', + componentProps: { disabled: true }, + }, + { + label: '种类名称', + field: 'kindName', + component: 'Input', + required: true, + }, + { + label: '对应分类', + field: 'categoryRefName', + component: 'Input', + componentProps: { disabled: true }, + }, + { + label: '优先级', + field: 'priority', + component: 'InputNumber', + required: true, + componentProps: { min: 0, precision: 0, style: { width: '100%' } }, + }, + { + label: '租户ID', + field: 'tenantId', + component: 'InputNumber', + componentProps: { disabled: true, style: { width: '100%' } }, + }, +]; + +export const batchJVxeColumns: JVxeColumn[] = [ + { title: '', key: 'categoryRefId', type: JVxeTypes.hidden }, + { title: '', key: 'categoryRefCode', type: JVxeTypes.hidden }, + { title: '', key: 'sourceType', type: JVxeTypes.hidden }, + { title: '', key: 'sourceRootCode', type: JVxeTypes.hidden }, + { title: '', key: 'sourceRootName', type: JVxeTypes.hidden }, + { title: '', key: 'tenantId', type: JVxeTypes.hidden }, + { title: '种类键值', key: 'kindKey', type: JVxeTypes.normal, width: 200, minWidth: 160, disabled: true }, + { title: '种类名称', key: 'kindName', type: JVxeTypes.input, width: 180, minWidth: 140 }, + { title: '对应分类', key: 'categoryRefName', type: JVxeTypes.normal, width: 180, minWidth: 140, disabled: true }, + { + title: '优先级', + key: 'priority', + type: JVxeTypes.inputNumber, + width: 110, + minWidth: 90, + align: 'center', + validateRules: [{ required: true, message: '请输入优先级' }], + }, +]; + +export const superQuerySchema = { + kindKey: { title: '种类键值', order: 0, view: 'text' }, + kindName: { title: '种类名称', order: 1, view: 'text' }, + sourceType: { title: '数据源', order: 2, view: 'list', enum: SOURCE_TYPE_OPTIONS }, + sourceRootCode: { title: '根编码', order: 3, view: 'text' }, + categoryRefName: { title: '对应分类', order: 4, view: 'text' }, + priority: { title: '优先级', order: 5, view: 'number' }, +}; diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfgList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfgList.vue new file mode 100644 index 0000000..bad582c --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfgList.vue @@ -0,0 +1,162 @@ + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgBatchModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgBatchModal.vue new file mode 100644 index 0000000..b17fc53 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgBatchModal.vue @@ -0,0 +1,189 @@ + + + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgEditModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgEditModal.vue new file mode 100644 index 0000000..1de8418 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgEditModal.vue @@ -0,0 +1,52 @@ + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts index 328081e..7a49e28 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts @@ -18,7 +18,10 @@ export const getExportUrl = Api.exportXls; export const getImportUrl = Api.importExcel; export const list = (params) => defHttp.get({ url: Api.list, params }); export const queryById = (params) => defHttp.get({ url: Api.queryById, params }); -export const saveOrUpdate = (params, isUpdate) => defHttp.post({ url: isUpdate ? Api.edit : Api.save, params }); +//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方主子表保存延长超时避免误报失败----------- +export const saveOrUpdate = (params, isUpdate) => + defHttp.post({ url: isUpdate ? Api.edit : Api.save, params, timeout: 60 * 1000 }); +//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方主子表保存延长超时避免误报失败----------- export const queryIssueNumberOptions = (params) => defHttp.get({ url: Api.queryIssueNumberOptions, params }); export const queryPurposeOptions = (params) => defHttp.get({ url: Api.queryPurposeOptions, params }); diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts index 415d138..2187215 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts @@ -91,10 +91,27 @@ export const materialColumns: JVxeColumn[] = [ { title: '物料大类', key: 'materialMajor', type: JVxeTypes.input, width: 100, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH }, { title: '物料小类', key: 'materialMinor', type: JVxeTypes.input, width: 120, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH }, { title: '种类', key: 'materialKind', type: JVxeTypes.input, width: 80, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH }, - { title: '密炼物料名称', key: 'mixerMaterialName', type: JVxeTypes.input, width: 160, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH }, + { + title: '密炼物料名称', + key: 'mixerMaterialName', + type: JVxeTypes.slot, + slotName: 'mixerMaterialNameSlot', + width: 160, + minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, + }, { title: '密炼物料描述', key: 'mixerMaterialDesc', type: JVxeTypes.input, width: 220, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH }, { title: '单重', key: 'unitWeight', type: JVxeTypes.inputNumber, width: 72, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, align: 'center' }, - { title: '累计', key: 'accumWeight', type: JVxeTypes.inputNumber, width: 72, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, align: 'center' }, + //update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】累计列按种类分组合计只读展示----------- + { + title: '累计', + key: 'accumWeight', + type: JVxeTypes.inputNumber, + width: 72, + minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, + align: 'center', + disabled: true, + }, + //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】累计列按种类分组合计只读展示----------- { title: '顺序', key: 'seqNo', type: JVxeTypes.inputNumber, width: 64, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, align: 'center' }, ]; @@ -196,6 +213,280 @@ export function calcMixingMaterialTableWidth(columns: JVxeColumn[], widthMap: Re } //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】橡胶及配合剂明细列展示设置----------- +//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计----------- +/** 是否为有效明细行(参与种类分组) */ +function isMixingMaterialDataRow(row: Recordable): boolean { + if (!row) { + return false; + } + return !!(row.mixerMaterialName || row.materialKind || row.unitWeight != null && row.unitWeight !== ''); +} + +/** 规范化种类字段,用于连续行分组 */ +function normalizeMixingMaterialKind(row: Recordable): string { + const kind = row?.materialKind; + return kind != null && String(kind).trim() !== '' ? String(kind).trim() : ''; +} + +/** 按种类连续分组,累计写入每组最后一行 */ +export function fillMixingMaterialAccumWeight(rows: Recordable[] = []): Recordable[] { + if (!rows?.length) { + return rows; + } + let index = 0; + while (index < rows.length) { + const current = rows[index]; + if (!isMixingMaterialDataRow(current)) { + current.accumWeight = null; + index++; + continue; + } + const kind = normalizeMixingMaterialKind(current); + let groupEnd = index; + let sum = 0; + while (groupEnd < rows.length) { + const row = rows[groupEnd]; + if (!isMixingMaterialDataRow(row) || normalizeMixingMaterialKind(row) !== kind) { + break; + } + const weight = toMixingMaterialNumber(row.unitWeight); + if (weight != null) { + sum += weight; + } + groupEnd++; + } + for (let rowIndex = index; rowIndex < groupEnd; rowIndex++) { + rows[rowIndex].accumWeight = + rowIndex === groupEnd - 1 && sum !== 0 ? roundMixingMaterialNumber(sum) : null; + } + index = groupEnd; + } + return rows; +} + +/** 安全解析明细数值,避免字符串拼接 */ +function toMixingMaterialNumber(value: unknown): number | null { + if (value == null || value === '') { + return null; + } + const num = Number(value); + return Number.isFinite(num) ? num : null; +} + +/** 混炼示方重量小数位(与后端 BigDecimal 精度一致) */ +const MIXING_MATERIAL_WEIGHT_SCALE = 6; + +/** 重量四舍五入,消除浮点累加误差 */ +function roundMixingMaterialNumber(value: number): number { + return Number(value.toFixed(MIXING_MATERIAL_WEIGHT_SCALE)); +} + +/** 格式化重量展示文本 */ +function formatMixingMaterialWeight(value: unknown): string { + const num = toMixingMaterialNumber(value); + if (num == null) { + return ''; + } + return String(roundMixingMaterialNumber(num)); +} + +//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A43】换算系数联动明细单重实时计算----------- +/** 规范化换算系数,空值或非正数按 1 处理 */ +export function normalizeMixingConvertFactor(factor: unknown): number { + const num = toMixingMaterialNumber(factor); + if (num == null || num <= 0) { + return 1; + } + return num; +} + +/** 基准单重 × 换算系数 */ +export function calcMixingMaterialConvertedWeight(base: unknown, factor: unknown): number | null { + const baseNum = toMixingMaterialNumber(base); + if (baseNum == null) { + return null; + } + return Number((baseNum * normalizeMixingConvertFactor(factor)).toFixed(MIXING_MATERIAL_WEIGHT_SCALE)); +} + +/** 从当前显示单重反推基准单重 */ +export function syncMaterialBaseUnitWeightFromDisplay(row: Recordable, factor: unknown) { + if (!row) { + return; + } + const unit = toMixingMaterialNumber(row.unitWeight); + if (unit == null) { + row.baseUnitWeight = null; + return; + } + row.baseUnitWeight = Number((unit / normalizeMixingConvertFactor(factor)).toFixed(MIXING_MATERIAL_WEIGHT_SCALE)); +} + +/** 初始化明细行基准单重(编辑加载时由已保存单重反推) */ +export function initMaterialBaseUnitWeight(row: Recordable, factor: unknown, force = false) { + if (!isMixingMaterialDataRow(row)) { + row.baseUnitWeight = null; + return; + } + if (!force && toMixingMaterialNumber(row.baseUnitWeight) != null) { + return; + } + syncMaterialBaseUnitWeightFromDisplay(row, factor); +} + +/** 批量初始化基准单重 */ +export function initMaterialBaseUnitWeights(rows: Recordable[] = [], factor: unknown, force = false) { + for (const row of rows) { + initMaterialBaseUnitWeight(row, factor, force); + } + return rows; +} + +/** 按换算系数重算所有明细单重 */ +export function applyConvertFactorToMaterialRows( + rows: Recordable[] = [], + factor: unknown, + prevFactor?: unknown, +): Recordable[] { + const nextFactor = normalizeMixingConvertFactor(factor); + const oldFactor = prevFactor != null ? normalizeMixingConvertFactor(prevFactor) : nextFactor; + for (const row of rows) { + if (!isMixingMaterialDataRow(row)) { + continue; + } + let base = toMixingMaterialNumber(row.baseUnitWeight); + if (base == null) { + const unit = toMixingMaterialNumber(row.unitWeight); + if (unit == null) { + continue; + } + base = roundMixingMaterialNumber(unit / oldFactor); + row.baseUnitWeight = base; + } + row.unitWeight = calcMixingMaterialConvertedWeight(base, nextFactor); + } + return rows; +} +//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A43】换算系数联动明细单重实时计算----------- + +//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A46】填充体积按单重/比重/机台有效体积自动计算----------- +/** 解析设备有效体积(支持纯数字或带单位字符串) */ +export function parseMixingEffectiveVolume(raw: unknown): number | null { + if (raw == null || raw === '') { + return null; + } + const text = String(raw).trim(); + if (!text) { + return null; + } + const direct = toMixingMaterialNumber(text); + if (direct != null && direct > 0) { + return direct; + } + const matched = text.match(/([0-9]+(?:\.[0-9]+)?)/); + if (!matched) { + return null; + } + const parsed = Number(matched[1]); + return Number.isFinite(parsed) && parsed > 0 ? parsed : null; +} + +/** 按段数与比重字段选择本段计算用比重 */ +export function resolveMixingSpecificGravity(form: Recordable = {}): number | null { + const motherSg = toMixingMaterialNumber(form.motherRubberSg); + const finalSg = toMixingMaterialNumber(form.finalRubberSg); + const stageCount = String(form.stageCount || '').trim(); + const stageMatch = stageCount.match(/^(\d+)\/(\d+)$/); + const isFinalStage = stageMatch ? stageMatch[1] === stageMatch[2] : false; + if (isFinalStage && finalSg != null && finalSg > 0) { + return finalSg; + } + if (motherSg != null && motherSg > 0) { + return motherSg; + } + if (finalSg != null && finalSg > 0) { + return finalSg; + } + return null; +} + +/** + * 填充体积(%) = 单重合计 ÷ 比重 ÷ 机台有效体积(L) × 100 + * 单重合计已含换算系数,此处不再重复乘换算系数 + */ +export function calcMixingFillVolume(totalWeight: unknown, specificGravity: unknown, effectiveVolume: unknown): number | null { + const weight = toMixingMaterialNumber(totalWeight); + const sg = toMixingMaterialNumber(specificGravity); + const volume = parseMixingEffectiveVolume(effectiveVolume); + if (weight == null || weight <= 0 || sg == null || sg <= 0 || volume == null || volume <= 0) { + return null; + } + const materialVolume = weight / sg; + return Number(((materialVolume / volume) * 100).toFixed(6)); +} +//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A46】填充体积按单重/比重/机台有效体积自动计算----------- + +/** 汇总有效明细行的单重合计 */ +export function calcMixingMaterialUnitWeightTotal(rows: Recordable[] = []): number | null { + let sum = 0; + let hasAny = false; + for (const row of rows) { + if (!isMixingMaterialDataRow(row)) { + continue; + } + const weight = toMixingMaterialNumber(row.unitWeight); + if (weight != null) { + sum += weight; + hasAny = true; + } + } + return hasAny ? roundMixingMaterialNumber(sum) : null; +} + +/** 汇总有效明细行的累计合计(与单重合计一致) */ +export function calcMixingMaterialAccumWeightTotal(rows: Recordable[] = []): number | null { + return calcMixingMaterialUnitWeightTotal(rows); +} + +export interface MixingMaterialFooterCell { + key: string; + width: number; + text: string; + align?: 'left' | 'center' | 'right'; + isLabel?: boolean; + isTotal?: boolean; +} + +/** 构建橡胶及配合剂明细底部合计行单元格(列宽与明细表同步) */ +export function buildMixingMaterialFooterCells( + columns: JVxeColumn[], + widthMap: Record, + totals: { unitWeight?: number | null; accumWeight?: number | null }, +): MixingMaterialFooterCell[] { + const unitWeightIndex = columns.findIndex((col) => String(col.key) === 'unitWeight'); + const formatTotal = (value: number | null | undefined) => formatMixingMaterialWeight(value); + + return columns.map((col, index) => { + const key = String(col.key); + const width = widthMap[key] ?? Number(col.width) ?? 80; + if (key === 'unitWeight') { + return { key, width, text: formatTotal(totals.unitWeight), align: 'center', isTotal: true }; + } + if (key === 'accumWeight') { + return { key, width, text: formatTotal(totals.accumWeight), align: 'center', isTotal: true }; + } + const isLabelCol = unitWeightIndex > 0 && index === unitWeightIndex - 1; + return { + key, + width, + text: isLabelCol ? '合计' : '', + align: 'center', + isLabel: isLabelCol, + }; + }); +} +//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计----------- + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A20】明细表默认列宽对齐参考图----------- /** 混合步骤/下密炼机明细列可缩小到的最小宽度 */ export const MIXING_STEP_MIN_COLUMN_WIDTH = 48; @@ -412,6 +703,9 @@ export const MIXING_VXE_MINI_HEADER_HEIGHT = 36; /** vxe mini 行高 */ export const MIXING_VXE_MINI_ROW_HEIGHT = 32; +/** 橡胶及配合剂明细合计行高度(含边框) */ +export const MIXING_MATERIAL_FOOTER_ROW_HEIGHT = MIXING_VXE_MINI_ROW_HEIGHT + 1; + //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A29】胶料/混合步骤表格高度按行数完整展示----------- /** 计算橡胶及配合剂明细表格展示高度 */ export function calcMixingMaterialTableHeight(rowCount = MIXING_MATERIAL_VISIBLE_ROW_COUNT) { @@ -637,3 +931,99 @@ export function ensureMixingDetailRows(rows: Recordable[] = [], defaultCount: nu } //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A39】编辑页明细补齐默认空行与新增一致----------- //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A22】明细表默认空行数----------- + +//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】混炼示方密炼物料选料弹窗与种类解析----------- +/** 混炼示方选料弹窗:隐藏的小类 ID 偏好 localStorage 键 */ +export const MIXING_MATERIAL_PICKER_HIDDEN_CATEGORY_CACHE_KEY = 'mes_xsl_mixing_spec_material_picker_hidden_categories'; + +export interface MixingMaterialPickerCategoryItem { + id: string; + name: string; + majorId: string; + majorName: string; + label: string; +} + +const mixingMaterialPickerStorage = createLocalStorage(); + +export function loadMixingMaterialPickerHiddenCategoryIds(): string[] { + const raw = mixingMaterialPickerStorage.get(MIXING_MATERIAL_PICKER_HIDDEN_CATEGORY_CACHE_KEY); + return Array.isArray(raw) ? raw.map(String) : []; +} + +export function saveMixingMaterialPickerHiddenCategoryIds(ids: string[]) { + mixingMaterialPickerStorage.set(MIXING_MATERIAL_PICKER_HIDDEN_CATEGORY_CACHE_KEY, ids || []); +} + +//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗小类树为空时重置隐藏配置----------- +/** 过滤无效隐藏项;若全部小类被隐藏则自动重置,避免左侧树只剩「全部小类」 */ +export function sanitizeMixingMaterialPickerHiddenCategoryIds(allMinorIds: string[], hidden: string[]) { + const allSet = new Set((allMinorIds || []).map(String)); + const filtered = (hidden || []).map(String).filter((id) => allSet.has(id)); + if (allSet.size > 0 && filtered.length >= allSet.size) { + return []; + } + return filtered; +} +//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗小类树为空时重置隐藏配置----------- + +/** 解析混炼示方明细种类:小类勾选胶料则显示「胶料」,否则显示小类名 */ +export function resolveMixingMaterialKindFromCategory(isRubber?: unknown, minorName?: string) { + if (isRubber === '1' || isRubber === 1 || isRubber === true) { + return '胶料'; + } + return minorName != null && String(minorName).trim() !== '' ? String(minorName).trim() : ''; +} + +//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗自动/人工称量列与种类映射----------- +/** 与配合示方「自动/人工」列相同字典 */ +export const MIXING_MATERIAL_PICKER_WEIGH_MODE_DICT = 'xslmes_formula_spec_weigh_mode'; + +/** 选料弹窗表格列(隐藏 ERP 编号,新增仅本次有效的自动/人工称量) */ +export const mixingMaterialPickerTableColumns: BasicColumn[] = [ + { title: '物料编码', align: 'center', width: 120, dataIndex: 'materialCode' }, + { title: '物料名称', align: 'center', width: 160, dataIndex: 'materialName' }, + { title: '自动/人工称量', align: 'center', width: 132, dataIndex: 'pickerWeighMode' }, + { title: '物料大类', align: 'center', width: 120, dataIndex: 'majorCategoryId_dictText' }, + { title: '物料小类', align: 'center', width: 120, dataIndex: 'minorCategoryId_dictText' }, + { title: '物料描述', align: 'center', width: 180, ellipsis: true, dataIndex: 'materialDesc' }, +]; + +/** 配合示方称量方式 -> 混炼示方种类(与后端 resolveWeighModeMaterialKind 一致) */ +export function resolveMixingMaterialKindFromWeighMode(weighMode?: string) { + if (weighMode == null || String(weighMode).trim() === '') { + return ''; + } + const normalized = String(weighMode).trim(); + const lower = normalized.toLowerCase(); + if (lower.startsWith('auto') || normalized.includes('自动')) { + return '自动'; + } + if (lower === 'manual' || normalized.includes('人工')) { + return '人工'; + } + return ''; +} + +/** 选料确认时种类:称量方式优先,否则按小类胶料/小类名 */ +export function resolveMixingMaterialKindForPicker(weighMode: string | undefined, isRubber?: unknown, minorName?: string) { + const fromWeighMode = resolveMixingMaterialKindFromWeighMode(weighMode); + if (fromWeighMode) { + return fromWeighMode; + } + return resolveMixingMaterialKindFromCategory(isRubber, minorName); +} +//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗自动/人工称量列与种类映射----------- + +/** 选择密炼物料后回填混炼示方橡胶及配合剂明细行 */ +export function applyMixingMaterialFromSelection(row: Recordable, material: Recordable, materialKind: string) { + if (!row || !material) { + return; + } + row.mixerMaterialName = material.materialName || material.materialCode || ''; + row.mixerMaterialDesc = material.materialDesc || material.materialName || material.materialCode || ''; + row.materialMajor = material.majorCategoryId_dictText || ''; + row.materialMinor = material.minorCategoryId_dictText || ''; + row.materialKind = materialKind || row.materialMinor || ''; +} +//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】混炼示方密炼物料选料弹窗与种类解析----------- diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue new file mode 100644 index 0000000..e4d6850 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue @@ -0,0 +1,221 @@ + + + + + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue new file mode 100644 index 0000000..9c28399 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue @@ -0,0 +1,406 @@ + + + + + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue index d1c244c..9db7a0d 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue @@ -55,7 +55,15 @@ 换算系数 - + 填充体积 @@ -80,7 +88,7 @@ 母胶比重 - + 段数 @@ -104,7 +112,7 @@ 终炼胶比重 - + 适用工厂 @@ -181,25 +189,60 @@
- + +
+
+ + + +
+ +
+
@@ -368,11 +411,11 @@
- - - + + + + + + + From 51cac2c17ab5fff348f92129439972603188c6a1 Mon Sep 17 00:00:00 2001 From: geht <2947093423@qq.com> Date: Tue, 26 May 2026 10:21:56 +0800 Subject: [PATCH 09/10] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B7=B7=E7=82=BC?= =?UTF-8?q?=E7=A4=BA=E6=96=B9=E9=80=89=E6=8B=A9=E5=BC=B9=E7=AA=97=E5=8F=8A?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=A7=84=E6=A0=BC=E9=80=89=E6=8B=A9=E4=B8=8E=E5=8F=82=E7=85=A7?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=8C=E4=BC=98=E5=8C=96=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BA=A4=E4=BA=92=E4=BD=93=E9=AA=8C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mesXslMixingSpec/MesXslMixingSpec.data.ts | 59 +++++ .../components/MesXslMixingSpecModal.vue | 112 +++++++-- .../MesXslMixingSpecSelectModal.vue | 236 ++++++++++++++++++ 3 files changed, 390 insertions(+), 17 deletions(-) create mode 100644 jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecSelectModal.vue diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts index 7b7ad45..05dfa7d 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts @@ -1185,3 +1185,62 @@ export const mixingSpecHistorySelectColumns: BasicColumn[] = [ }, ]; //update-end---author:cursor ---date:20260526 for:【XSLMES-20260526-A58】参照历史混合步骤选择弹窗----------- + +//update-begin---author:cursor ---date:20260526 for:【XSLMES-20260526-A59】规格点击选择混炼示方及参照新增----------- +/** 参照新增时需剔除的主表字段 */ +export const MIXING_SPEC_MAIN_STRIP_FIELDS = [ + 'id', + 'createBy', + 'createTime', + 'updateBy', + 'updateTime', + 'draftBy', + 'draftTime', + 'proofreadBy', + 'proofreadTime', + 'auditBy', + 'auditTime', + 'approveBy', + 'approveTime', + 'changeDate', + 'delFlag', + 'tenantId', + 'sysOrgCode', +] as const; + +/** 参照新增时需剔除的明细字段 */ +export const MIXING_SPEC_CHILD_STRIP_FIELDS = [ + 'id', + 'mixingSpecId', + 'createBy', + 'createTime', + 'updateBy', + 'updateTime', + 'tenantId', +] as const; + +/** 参照选中示方新增:复制除 ID 及审计字段外的全部数据 */ +export function cloneMixingSpecPageForReferenceAdd(source: Recordable = {}): Recordable { + const main: Recordable = { ...source }; + MIXING_SPEC_MAIN_STRIP_FIELDS.forEach((key) => delete main[key]); + main.id = ''; + + const cloneChildList = (rows: Recordable[] = []) => + normalizeMixingDetailRows( + (rows || []).map((row) => { + const next: Recordable = { ...row }; + MIXING_SPEC_CHILD_STRIP_FIELDS.forEach((key) => delete next[key]); + delete next.baseUnitWeight; + return next; + }), + ); + + return { + ...main, + materialList: cloneChildList(source.materialList), + stepList: cloneChildList(source.stepList), + downStepList: cloneChildList(source.downStepList), + tcuList: cloneChildList(source.tcuList), + }; +} +//update-end---author:cursor ---date:20260526 for:【XSLMES-20260526-A59】规格点击选择混炼示方及参照新增----------- diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue index 31ca379..3f61b6a 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue @@ -20,7 +20,15 @@ 规格 - + 机台 制作日期 @@ -421,6 +429,7 @@ + + + + + From e6241c16c7831a7c2cc8d04a16a0b92f9c99ed1d Mon Sep 17 00:00:00 2001 From: geht <2947093423@qq.com> Date: Tue, 26 May 2026 10:26:53 +0800 Subject: [PATCH 10/10] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B7=B7=E7=82=BC?= =?UTF-8?q?=E7=A4=BA=E6=96=B9=E4=B8=AD=E6=8D=A2=E7=AE=97=E7=B3=BB=E6=95=B0?= =?UTF-8?q?=E5=92=8C=E9=85=8D=E6=96=B9=E5=8F=82=E6=95=B0=E7=9A=84=E6=95=B0?= =?UTF-8?q?=E5=80=BC=E5=B1=95=E7=A4=BA=E4=B8=8E=E8=BE=93=E5=85=A5=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=EF=BC=8C=E8=B0=83=E6=95=B4=E7=9B=B8=E5=85=B3=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E7=9A=84=E5=B0=8F=E6=95=B0=E7=B2=BE=E5=BA=A6=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E7=94=A8=E6=88=B7=E4=BA=A4=E4=BA=92=E4=BD=93?= =?UTF-8?q?=E9=AA=8C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mesXslMixingSpec/MesXslMixingSpec.data.ts | 75 ++++++++++++++++- .../components/MesXslMixingSpecModal.vue | 82 +++++++++++++++++-- 2 files changed, 150 insertions(+), 7 deletions(-) diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts index 05dfa7d..a30678a 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts @@ -57,7 +57,7 @@ export const mainSchema: FormSchema[] = [ { label: '制作日期', field: 'makeDate', component: 'DatePicker', colProps: { span: 8 }, componentProps: { valueFormat: 'YYYY-MM-DD' } }, { label: '发行编号', field: 'issueNumber', component: 'Input', required: true, colProps: { span: 8 } }, //update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A33】混炼示方基本信息字段优化----------- - { label: '换算系数', field: 'convertFactor', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, + { label: '换算系数', field: 'convertFactor', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 2, style: { width: '100%' } } }, { label: '填充体积', field: 'fillVolume', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, { label: '回收炭黑(秒)', field: 'recycleCarbonSec', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } }, { label: '母胶比重', field: 'motherRubberSg', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } }, @@ -279,6 +279,79 @@ function toMixingMaterialNumber(value: unknown): number | null { /** 混炼示方重量小数位(与后端 BigDecimal 精度一致) */ const MIXING_MATERIAL_WEIGHT_SCALE = 6; +//update-begin---author:cursor ---date:20260526 for:【XSLMES-20260526-A60】换算系数/配方参数数值展示优化----------- +/** 换算系数展示小数位 */ +export const MIXING_CONVERT_FACTOR_SCALE = 2; + +/** 配方参数设定允许的小数精度 */ +export const MIXING_RECIPE_PARAM_DECIMAL_SCALE = 6; + +/** 配方参数设定:允许小数的字段 */ +export const MIXING_RECIPE_PARAM_DECIMAL_FIELDS = [ + 'sideWallWaterTemp', + 'overtempDischargeTemp', + 'doorWaterTemp', + 'rotorWaterTemp', + 'maxFeedTemp', +] as const; + +/** 换算系数展示:固定保留两位小数 */ +export function formatMixingConvertFactorDisplay(value: unknown): string { + if (value === null || value === undefined || value === '') { + return ''; + } + const num = Number(value); + if (Number.isNaN(num)) { + return String(value); + } + return num.toFixed(MIXING_CONVERT_FACTOR_SCALE); +} + +/** 换算系数输入解析 */ +export function parseMixingConvertFactorValue(value: unknown): number | null { + if (value === '' || value == null) { + return null; + } + const num = Number(String(value).replace(/,/g, '').trim()); + if (Number.isNaN(num)) { + return null; + } + return Number(num.toFixed(MIXING_CONVERT_FACTOR_SCALE)); +} + +/** 配方参数展示:允许小数,无小数部分时仅展示整数 */ +export function formatMixingRecipeParamDisplay(value: unknown, maxPrecision = MIXING_RECIPE_PARAM_DECIMAL_SCALE): string { + if (value === null || value === undefined || value === '') { + return ''; + } + const num = Number(value); + if (Number.isNaN(num)) { + return String(value); + } + const rounded = Number(num.toFixed(maxPrecision)); + if (Number.isInteger(rounded)) { + return String(rounded); + } + return String(rounded); +} + +/** 配方参数输入解析 */ +export function parseMixingRecipeParamValue(value: unknown): number | null { + if (value === '' || value == null) { + return null; + } + const text = String(value).replace(/,/g, '').trim(); + if (!text) { + return null; + } + const num = Number(text); + if (Number.isNaN(num)) { + return null; + } + return Number(num.toFixed(MIXING_RECIPE_PARAM_DECIMAL_SCALE)); +} +//update-end---author:cursor ---date:20260526 for:【XSLMES-20260526-A60】换算系数/配方参数数值展示优化----------- + /** 重量四舍五入,消除浮点累加误差 */ function roundMixingMaterialNumber(value: number): number { return Number(value.toFixed(MIXING_MATERIAL_WEIGHT_SCALE)); diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue index 3f61b6a..6b8c87a 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue @@ -67,7 +67,9 @@ 侧壁水温 - + 超时排胶时间 @@ -158,21 +168,53 @@ 超温排胶温度 - + 卸料门水温 - + 转子水温 - + 最高进料温度 - + @@ -474,6 +516,10 @@ import { calcMixingMaterialAccumWeightTotal, buildMixingMaterialFooterCells, normalizeMixingConvertFactor, + formatMixingConvertFactorDisplay, + parseMixingConvertFactorValue, + formatMixingRecipeParamDisplay, + parseMixingRecipeParamValue, initMaterialBaseUnitWeights, applyConvertFactorToMaterialRows, syncMaterialBaseUnitWeightFromDisplay, @@ -682,6 +728,30 @@ function stripMaterialRowForSave(row: Recordable) { const { baseUnitWeight: _baseUnitWeight, ...rest } = row; return rest; } + +//update-begin---author:cursor ---date:20260526 for:【XSLMES-20260526-A60】换算系数/配方参数数值展示优化----------- +function formatConvertFactorInput(value: string | number, info?: { userTyping?: boolean }) { + if (info?.userTyping) { + return value == null ? '' : String(value); + } + return formatMixingConvertFactorDisplay(value); +} + +function parseConvertFactorInput(value: string) { + return parseMixingConvertFactorValue(value); +} + +function formatRecipeParamInput(value: string | number, info?: { userTyping?: boolean }) { + if (info?.userTyping) { + return value == null ? '' : String(value); + } + return formatMixingRecipeParamDisplay(value); +} + +function parseRecipeParamInput(value: string) { + return parseMixingRecipeParamValue(value); +} +//update-end---author:cursor ---date:20260526 for:【XSLMES-20260526-A60】换算系数/配方参数数值展示优化----------- //update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A43】换算系数联动明细单重实时计算----------- function recalcMaterialAccumWeight() {