diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 new file mode 100644 index 0000000..419402b --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/doc/代码修改日志 @@ -0,0 +1,105 @@ +-- author:jiangxh---date:20260521--for: 【配合示方】新增配合示方主子表模块 --- +jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_91__mes_xsl_formula_spec.sql +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpec.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpecLine.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaSpecPage.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecMapper.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecLineMapper.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/MesXslFormulaSpecList.vue +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue + +-- author:jiangxh---date:20260521--for: 【配合示方】主表新增混合段1-7合计字段 --- +jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_92__mes_xsl_formula_spec_stage_total.sql +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpec.java +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue + +-- author:cursor---date:20260521--for: 【配合示方】STEP全为A/Q时对应胶比重清零 --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue + +-- author:cursor---date:20260521--for: 【配合示方】含胶率按密炼物料小类汇总重量% --- +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue +jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSelectModal.vue + +-- author:cursor---date:20260521--for: 【配合示方】含胶率物料小类可配置设置弹窗 --- +jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_96__mes_xsl_formula_spec_rubber_content_setting.sql +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpecSetting.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaRubberContentSettingVO.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecSettingMapper.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecSettingService.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecSettingServiceImpl.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslFormulaSpecController.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaRubberContentSettingModal.vue + +-- author:cursor---date:20260521--for: 【配合示方】含胶率设置改用系统MES物料分类字典 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaRubberContentSettingModal.vue +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecSettingService.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecSettingServiceImpl.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslFormulaSpecController.java + +-- author:cursor---date:20260521--for: 【配合示方】含胶率设置小类下拉对齐密炼物料loadTreeData加载 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaRubberContentSettingModal.vue + +-- author:cursor---date:20260521--for: 【配合示方】含胶率设置改为loadAllData加载MES物料分类全部节点 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaRubberContentSettingModal.vue + +-- author:cursor---date:20260521--for: 【配合示方】含胶率设置弹窗openModal未传data导致不加载分类 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaRubberContentSettingModal.vue + +-- author:cursor---date:20260521--for: 【配合示方】明细新增物料大类/小类展示列(不落库) --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue +jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSelectModal.vue + +-- author:cursor---date:20260521--for: 【配合示方】明细备注列与1-7段列宽适当缩小 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts + +-- author:cursor---date:20260521--for: 【配合示方】基本信息模块改为汇总格状布局 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue + +-- author:cursor---date:20260521--for: 【配合示方】基本信息改为显式表格格状布局 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts + +-- author:cursor---date:20260521--for: 【配合示方】汇总与基本信息标题格增加内阴影 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue + +-- author:cursor---date:20260521--for: 【配合示方】明细列表新增列显示/隐藏设置 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaLineColumnSetting.vue + +-- author:cursor---date:20260521--for: 【配合示方】明细列表列设置改为保存后生效并修复勾选状态 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaLineColumnSetting.vue + +-- author:cursor---date:20260521--for: 【配合示方】审批进度编制人展示真实姓名 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpec.java +jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java + +-- author:cursor---date:20260521--for: 【配合示方】编辑页A胶TOTAL PHR缺失时按明细补算回显 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue + +-- author:cursor---date:20260521--for: 【配合示方】编辑打开时基本资料闪清修复 --- +jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.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 new file mode 100644 index 0000000..0ad744a --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslFormulaSpecController.java @@ -0,0 +1,208 @@ +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.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +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.system.base.controller.JeecgController; +import org.jeecg.common.system.query.QueryGenerator; +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.service.IMesXslFormulaSpecService; +import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecSettingService; +import org.jeecg.modules.xslmes.vo.MesXslFormulaRubberContentSettingVO; +import org.jeecg.modules.xslmes.vo.MesXslFormulaSpecPage; +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/mesXslFormulaSpec") +@Slf4j +public class MesXslFormulaSpecController extends JeecgController { + + @Autowired + private IMesXslFormulaSpecService mesXslFormulaSpecService; + + @Autowired + private IMesXslFormulaSpecSettingService mesXslFormulaSpecSettingService; + + @Operation(summary = "MES配合示方-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList( + MesXslFormulaSpec 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()); + if (oConvertUtils.isNotEmpty(keyword)) { + queryWrapper.and( + w -> w.like("spec_code", keyword) + .or() + .like("rubber_code", keyword) + .or() + .like("issue_number", keyword) + .or() + .like("purpose", keyword)); + } + queryWrapper.orderByDesc("update_time").orderByDesc("create_time"); + Page page = new Page<>(pageNo, pageSize); + IPage pageList = mesXslFormulaSpecService.page(page, queryWrapper); + return Result.OK(pageList); + } + + @AutoLog(value = "MES配合示方-添加") + @Operation(summary = "MES配合示方-添加") + @RequiresPermissions("xslmes:mes_xsl_formula_spec:add") + @PostMapping(value = "/add") + public Result add(@RequestBody MesXslFormulaSpecPage page) { + //update-begin---author:jiangxh ---date:20260521 for:【配合示方】主子表保存校验----------- + String err = validateMain(page); + if (err != null) { + return Result.error(err); + } + //update-end---author:jiangxh ---date:20260521 for:【配合示方】主子表保存校验----------- + MesXslFormulaSpec main = new MesXslFormulaSpec(); + BeanUtils.copyProperties(page, main); + mesXslFormulaSpecService.saveMain(main, page.getLineList()); + return Result.OK("添加成功!"); + } + + @AutoLog(value = "MES配合示方-编辑") + @Operation(summary = "MES配合示方-编辑") + @RequiresPermissions("xslmes:mes_xsl_formula_spec:edit") + @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST}) + public Result edit(@RequestBody MesXslFormulaSpecPage page) { + //update-begin---author:jiangxh ---date:20260521 for:【配合示方】主子表保存校验----------- + String err = validateMain(page); + if (err != null) { + return Result.error(err); + } + //update-end---author:jiangxh ---date:20260521 for:【配合示方】主子表保存校验----------- + MesXslFormulaSpec main = new MesXslFormulaSpec(); + BeanUtils.copyProperties(page, main); + mesXslFormulaSpecService.updateMain(main, page.getLineList()); + return Result.OK("编辑成功!"); + } + + @AutoLog(value = "MES配合示方-删除") + @Operation(summary = "MES配合示方-通过id删除") + @RequiresPermissions("xslmes:mes_xsl_formula_spec:delete") + @DeleteMapping(value = "/delete") + public Result delete(@RequestParam(name = "id", required = true) String id) { + mesXslFormulaSpecService.delMain(id); + return Result.OK("删除成功!"); + } + + @AutoLog(value = "MES配合示方-批量删除") + @Operation(summary = "MES配合示方-批量删除") + @RequiresPermissions("xslmes:mes_xsl_formula_spec:deleteBatch") + @DeleteMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) { + mesXslFormulaSpecService.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) { + MesXslFormulaSpec entity = mesXslFormulaSpecService.getByIdWithLines(id); + if (entity == null) { + return Result.error("未找到对应数据"); + } + return Result.OK(entity); + } + + @Operation(summary = "MES配合示方-查询明细") + @GetMapping(value = "/queryLineListByMainId") + public Result> queryLineListByMainId(@RequestParam(name = "id", required = true) String id) { + return Result.OK(mesXslFormulaSpecService.selectLinesByMainId(id)); + } + + //update-begin---author:cursor ---date:20260521 for:配合示方胶料代号自动生成----------- + @Operation(summary = "MES配合示方-生成胶料代号") + @GetMapping(value = "/generateRubberCode") + public Result> generateRubberCode( + @RequestParam(name = "rubberMaterialId") String rubberMaterialId, + @RequestParam(name = "category") String category, + @RequestParam(name = "excludeSpecId", required = false) String excludeSpecId) { + try { + String rubberCode = mesXslFormulaSpecService.generateRubberCode(rubberMaterialId, category, excludeSpecId); + return Result.OK(Map.of("rubberCode", rubberCode)); + } catch (IllegalArgumentException ex) { + return Result.error(ex.getMessage()); + } + } + //update-end---author:cursor ---date:20260521 for:配合示方胶料代号自动生成----------- + + //update-begin---author:cursor ---date:20260521 for:【配合示方】含胶率物料小类可配置----------- + @Operation(summary = "MES配合示方-查询含胶率物料小类配置") + @GetMapping(value = "/getRubberContentSetting") + public Result getRubberContentSetting() { + return Result.OK(mesXslFormulaSpecSettingService.getRubberContentSetting()); + } + + @AutoLog(value = "MES配合示方-保存含胶率物料小类配置") + @Operation(summary = "MES配合示方-保存含胶率物料小类配置") + @RequiresPermissions("xslmes:mes_xsl_formula_spec:edit") + @PostMapping(value = "/saveRubberContentSetting") + public Result saveRubberContentSetting(@RequestBody MesXslFormulaRubberContentSettingVO setting) { + mesXslFormulaSpecSettingService.saveRubberContentSetting(setting); + return Result.OK("保存成功"); + } + //update-end---author:cursor ---date:20260521 for:【配合示方】含胶率物料小类可配置----------- + + @RequiresPermissions("xslmes:mes_xsl_formula_spec:exportXls") + @RequestMapping(value = "/exportXls") + public ModelAndView exportXls(HttpServletRequest request, MesXslFormulaSpec model) { + return super.exportXls(request, model, MesXslFormulaSpec.class, "配合示方"); + } + + @RequiresPermissions("xslmes:mes_xsl_formula_spec:importExcel") + @RequestMapping(value = "/importExcel", method = RequestMethod.POST) + public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + return super.importExcel(request, response, MesXslFormulaSpec.class); + } + + //update-begin---author:jiangxh ---date:20260521 for:【配合示方】主子表保存校验----------- + private String validateMain(MesXslFormulaSpecPage page) { + if (oConvertUtils.isEmpty(page.getSpecCode())) { + return "请输入示方编号"; + } + if (oConvertUtils.isEmpty(page.getRubberCode())) { + return "请选择胶料并生成胶料代号"; + } + if (oConvertUtils.isEmpty(page.getRubberMaterialId())) { + return "请选择胶料信息"; + } + if (page.getMixingStages() != null && (page.getMixingStages() < 1 || page.getMixingStages() > 7)) { + return "混合段数必须在1-7之间"; + } + if (page.getLineList() == null || page.getLineList().isEmpty()) { + return "请至少添加一行配合明细"; + } + return null; + } + //update-end---author:jiangxh ---date:20260521 for:【配合示方】主子表保存校验----------- +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpec.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpec.java new file mode 100644 index 0000000..474910f --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpec.java @@ -0,0 +1,220 @@ +package org.jeecg.modules.xslmes.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +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 java.util.List; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.jeecg.common.aspect.annotation.Dict; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.springframework.format.annotation.DateTimeFormat; + +/** + * MES 配合示方 + */ +@Data +@TableName("mes_xsl_formula_spec") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "MES配合示方") +public class MesXslFormulaSpec implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Excel(name = "分类", width = 10, dicCode = "xslmes_formula_spec_category") + @Dict(dicCode = "xslmes_formula_spec_category") + @Schema(description = "分类") + private String category; + + @Excel(name = "示方编号", width = 18) + @Schema(description = "示方编号") + private String specCode; + + @Excel(name = "胶料代号", width = 18) + @Schema(description = "胶料代号") + private String rubberCode; + + @Schema(description = "胶料ID(关联mes_material.id)") + private String rubberMaterialId; + + @Excel(name = "基本配合", width = 15) + @Schema(description = "基本配合") + private String basicFormula; + + @Excel(name = "发行日期", width = 15, format = "yyyy-MM-dd") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @Schema(description = "发行日期") + private Date issueDate; + + @Excel(name = "用途", width = 20) + @Schema(description = "用途") + private String purpose; + + @Excel(name = "发行编号", width = 15) + @Schema(description = "发行编号") + private String issueNumber; + + @Excel(name = "混合段数", width = 10) + @Schema(description = "混合段数") + private Integer mixingStages; + + @Excel(name = "混合机器", width = 15) + @Schema(description = "混合机器") + private String mixingMachine; + + @Schema(description = "发行部门ID") + private String issueDeptId; + + @Excel(name = "发行部门", width = 15) + @Schema(description = "发行部门名称") + private String issueDeptName; + + @Excel(name = "A胶TOTAL PHR", width = 14) + @Schema(description = "A胶TOTAL PHR") + private BigDecimal aRubberTotalPhr; + + @Excel(name = "TOTAL PHR", width = 12) + @Schema(description = "TOTAL PHR") + private BigDecimal totalPhr; + + //update-begin---author:jiangxh ---date:20260521 for:【配合示方】主表新增混合段1-7合计字段----------- + @Excel(name = "混合段1合计", width = 12) + @Schema(description = "混合段1合计") + private BigDecimal stage1Total; + + @Excel(name = "混合段2合计", width = 12) + @Schema(description = "混合段2合计") + private BigDecimal stage2Total; + + @Excel(name = "混合段3合计", width = 12) + @Schema(description = "混合段3合计") + private BigDecimal stage3Total; + + @Excel(name = "混合段4合计", width = 12) + @Schema(description = "混合段4合计") + private BigDecimal stage4Total; + + @Excel(name = "混合段5合计", width = 12) + @Schema(description = "混合段5合计") + private BigDecimal stage5Total; + + @Excel(name = "混合段6合计", width = 12) + @Schema(description = "混合段6合计") + private BigDecimal stage6Total; + + @Excel(name = "混合段7合计", width = 12) + @Schema(description = "混合段7合计") + private BigDecimal stage7Total; + //update-end---author:jiangxh ---date:20260521 for:【配合示方】主表新增混合段1-7合计字段----------- + + @Excel(name = "发行理由", width = 30) + @Schema(description = "发行理由") + private String issueReason; + + @Excel(name = "天然橡胶", width = 12) + @Schema(description = "天然橡胶") + private BigDecimal naturalRubber; + + @Excel(name = "合成橡胶", width = 12) + @Schema(description = "合成橡胶") + private BigDecimal syntheticRubber; + + @Excel(name = "合计", width = 12) + @Schema(description = "合计") + private BigDecimal totalAmount; + + @Excel(name = "重量单价", width = 12) + @Schema(description = "重量单价") + private BigDecimal weightUnitPrice; + + @Excel(name = "体积单价", width = 12) + @Schema(description = "体积单价") + private BigDecimal volumeUnitPrice; + + @Excel(name = "Q胶比重", width = 12) + @Schema(description = "Q胶比重") + @TableField("q_rubber_sg") + private BigDecimal qRubberSg; + + @Excel(name = "A胶比重", width = 12) + @Schema(description = "A胶比重") + @TableField("a_rubber_sg") + private BigDecimal aRubberSg; + + @Excel(name = "人工配料", width = 10, replace = {"是_1", "否_0"}) + @Schema(description = "是否有人工配料(0否 1是)") + private Integer hasManualBatch; + + @Excel(name = "状态", width = 12, dicCode = "xslmes_formula_spec_status") + @Dict(dicCode = "xslmes_formula_spec_status") + @Schema(description = "状态") + private String status; + + @Excel(name = "校对人", width = 12) + @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; + + @Excel(name = "审核人", width = 12) + @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; + + @Excel(name = "批准人", width = 12) + @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; + + @Excel(name = "创建人", width = 12, dictTable = "sys_user", dicText = "realname", dicCode = "username") + @Dict(dictTable = "sys_user", dicText = "realname", dicCode = "username") + private String createBy; + + /** queryById 等非分页接口补充创建人姓名(DictAspect 仅翻译分页列表) */ + @TableField(exist = false) + @Schema(description = "创建人姓名") + private String createBy_dictText; + + @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; + + @Schema(description = "租户ID") + private Integer tenantId; + + private String sysOrgCode; + private Integer delFlag; + + @TableField(exist = false) + @Schema(description = "配合明细") + private List lineList; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpecLine.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpecLine.java new file mode 100644 index 0000000..fe18d49 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpecLine.java @@ -0,0 +1,105 @@ +package org.jeecg.modules.xslmes.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.jeecg.common.aspect.annotation.Dict; +import org.springframework.format.annotation.DateTimeFormat; + +/** + * MES 配合示方明细 + */ +@Data +@TableName("mes_xsl_formula_spec_line") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "MES配合示方明细") +public class MesXslFormulaSpecLine implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Schema(description = "配合示方主表ID") + private String formulaSpecId; + + @Schema(description = "行序号") + private Integer sortNo; + + @Schema(description = "PHR") + private BigDecimal phr; + + @Schema(description = "密炼物料ID") + private String mixerMaterialId; + + @Schema(description = "密炼物料编码") + private String mixerMaterialCode; + + @Schema(description = "密炼物料名称") + private String mixerMaterialName; + + @Schema(description = "物料描述") + private String materialDesc; + + @Dict(dicCode = "xslmes_formula_spec_step") + @Schema(description = "STEP") + private String step; + + @Dict(dicCode = "xslmes_formula_spec_weigh_mode") + @Schema(description = "称量方式") + private String weighMode; + + @Schema(description = "重量%") + private BigDecimal weightPercent; + + @Schema(description = "体积") + private BigDecimal volume; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "混合段1") + private BigDecimal stage1; + + @Schema(description = "混合段2") + private BigDecimal stage2; + + @Schema(description = "混合段3") + private BigDecimal stage3; + + @Schema(description = "混合段4") + private BigDecimal stage4; + + @Schema(description = "混合段5") + private BigDecimal stage5; + + @Schema(description = "混合段6") + private BigDecimal stage6; + + @Schema(description = "混合段7") + private BigDecimal stage7; + + @Schema(description = "租户ID") + private Integer tenantId; + + private String createBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + private String updateBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpecSetting.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpecSetting.java new file mode 100644 index 0000000..9e5b421 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslFormulaSpecSetting.java @@ -0,0 +1,48 @@ +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.springframework.format.annotation.DateTimeFormat; + +/** + * 配合示方模块配置 + */ +@Data +@TableName("mes_xsl_formula_spec_setting") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "配合示方模块配置") +public class MesXslFormulaSpecSetting implements Serializable { + private static final long serialVersionUID = 1L; + + public static final String DEFAULT_ID = "1993000000000000991"; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Schema(description = "天然橡胶物料小类ID,逗号分隔") + private String naturalMinorCategoryIds; + + @Schema(description = "合成橡胶物料小类ID,逗号分隔") + private String syntheticMinorCategoryIds; + + private String createBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + private String updateBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecLineMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecLineMapper.java new file mode 100644 index 0000000..e3a13a1 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecLineMapper.java @@ -0,0 +1,6 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine; + +public interface MesXslFormulaSpecLineMapper extends BaseMapper {} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecMapper.java new file mode 100644 index 0000000..bce5880 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecMapper.java @@ -0,0 +1,6 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec; + +public interface MesXslFormulaSpecMapper extends BaseMapper {} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecSettingMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecSettingMapper.java new file mode 100644 index 0000000..959bf3b --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslFormulaSpecSettingMapper.java @@ -0,0 +1,7 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecSetting; + +public interface MesXslFormulaSpecSettingMapper extends BaseMapper { +} 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 new file mode 100644 index 0000000..65f453b --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java @@ -0,0 +1,28 @@ +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 org.jeecg.modules.xslmes.entity.MesXslFormulaSpec; +import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine; + +public interface IMesXslFormulaSpecService extends IService { + + void saveMain(MesXslFormulaSpec main, List lineList); + + void updateMain(MesXslFormulaSpec main, List lineList); + + void delMain(String id); + + void delBatchMain(Collection idList); + + List selectLinesByMainId(String mainId); + + MesXslFormulaSpec getByIdWithLines(String id); + + /** + * 生成胶料代号:D + 胶料名称 + 分类键值(S/P/T/C) + 版本号(A01-Z01) + */ + String generateRubberCode(String rubberMaterialId, String category, String excludeSpecId); +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecSettingService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecSettingService.java new file mode 100644 index 0000000..0702227 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecSettingService.java @@ -0,0 +1,17 @@ +package org.jeecg.modules.xslmes.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import java.util.Set; +import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecSetting; +import org.jeecg.modules.xslmes.vo.MesXslFormulaRubberContentSettingVO; + +public interface IMesXslFormulaSpecSettingService extends IService { + + MesXslFormulaRubberContentSettingVO getRubberContentSetting(); + + void saveRubberContentSetting(MesXslFormulaRubberContentSettingVO setting); + + Set getNaturalMinorCategoryIds(); + + Set getSyntheticMinorCategoryIds(); +} 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 new file mode 100644 index 0000000..cdb7d34 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java @@ -0,0 +1,403 @@ +package org.jeecg.modules.xslmes.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import java.io.Serializable; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; +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.modules.xslmes.entity.MesXslFormulaSpec; +import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine; +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.system.entity.SysUser; +import org.jeecg.modules.system.service.ISysUserService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +@Service +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$"); + + @Resource + private MesXslFormulaSpecLineMapper lineMapper; + + @Resource + private IMesMixerMaterialService mesMixerMaterialService; + + @Resource + private IMesMaterialService mesMaterialService; + + @Resource + private IMesXslFormulaSpecSettingService mesXslFormulaSpecSettingService; + + @Resource + private ISysUserService sysUserService; + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveMain(MesXslFormulaSpec main, List lineList) { + fillMainDefaults(main); + //update-begin---author:cursor ---date:20260521 for:配合示方新增时服务端生成胶料代号----------- + fillRubberCodeOnCreate(main); + //update-end---author:cursor ---date:20260521 for:配合示方新增时服务端生成胶料代号----------- + this.save(main); + insertLines(main, lineList); + refreshMainSummary(main.getId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateMain(MesXslFormulaSpec main, List lineList) { + fillMainDefaults(main); + this.updateById(main); + lineMapper.delete(new LambdaQueryWrapper().eq(MesXslFormulaSpecLine::getFormulaSpecId, main.getId())); + insertLines(main, lineList); + refreshMainSummary(main.getId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delMain(String id) { + lineMapper.delete(new LambdaQueryWrapper().eq(MesXslFormulaSpecLine::getFormulaSpecId, id)); + this.removeById(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delBatchMain(Collection idList) { + if (idList == null || idList.isEmpty()) { + return; + } + for (Serializable id : idList) { + if (id != null) { + delMain(id.toString()); + } + } + } + + @Override + public List selectLinesByMainId(String mainId) { + return lineMapper.selectList( + new LambdaQueryWrapper() + .eq(MesXslFormulaSpecLine::getFormulaSpecId, mainId) + .orderByAsc(MesXslFormulaSpecLine::getSortNo) + .orderByAsc(MesXslFormulaSpecLine::getId)); + } + + @Override + public MesXslFormulaSpec getByIdWithLines(String id) { + MesXslFormulaSpec main = this.getById(id); + if (main == null) { + return null; + } + main.setLineList(selectLinesByMainId(id)); + //update-begin---author:cursor ---date:20260521 for:【配合示方】queryById补充创建人姓名供审批进度展示----------- + fillCreateByDictText(main); + //update-end---author:cursor ---date:20260521 for:【配合示方】queryById补充创建人姓名供审批进度展示----------- + return main; + } + + private void fillCreateByDictText(MesXslFormulaSpec main) { + if (main == null || StringUtils.isBlank(main.getCreateBy())) { + return; + } + SysUser user = sysUserService.getUserByName(main.getCreateBy()); + if (user != null && StringUtils.isNotBlank(user.getRealname())) { + main.setCreateBy_dictText(user.getRealname()); + } + } + + //update-begin---author:cursor ---date:20260521 for:配合示方胶料代号自动生成 D+胶料名称+分类+版本号----------- + @Override + public String generateRubberCode(String rubberMaterialId, String category, String excludeSpecId) { + if (StringUtils.isBlank(rubberMaterialId)) { + throw new IllegalArgumentException("请选择胶料信息"); + } + if (StringUtils.isBlank(category) || !RUBBER_CATEGORY_KEYS.contains(category)) { + throw new IllegalArgumentException("请选择有效的示方分类"); + } + MesMaterial material = mesMaterialService.getById(rubberMaterialId); + if (material == null || StringUtils.isBlank(material.getMaterialName())) { + throw new IllegalArgumentException("所选胶料不存在或未维护胶料名称"); + } + String basePrefix = buildRubberCodePrefix(material.getMaterialName(), category); + Set usedLetters = loadUsedRubberCodeLetters(rubberMaterialId, category, basePrefix, excludeSpecId); + for (char letter = 'A'; letter <= 'Z'; letter++) { + if (!usedLetters.contains(letter)) { + return basePrefix + letter + "01"; + } + } + throw new IllegalArgumentException("该胶料在当前分类下的代号版本已用尽(A01-Z01)"); + } + + private void fillRubberCodeOnCreate(MesXslFormulaSpec main) { + if (StringUtils.isBlank(main.getRubberMaterialId()) || StringUtils.isBlank(main.getCategory())) { + return; + } + main.setRubberCode(generateRubberCode(main.getRubberMaterialId(), main.getCategory(), null)); + main.setSpecCode(main.getRubberCode()); + } + + private String buildRubberCodePrefix(String materialName, String category) { + return "D" + materialName.trim() + category; + } + + private Set loadUsedRubberCodeLetters( + String rubberMaterialId, String category, String basePrefix, String excludeSpecId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(MesXslFormulaSpec::getRubberMaterialId, rubberMaterialId) + .eq(MesXslFormulaSpec::getCategory, category) + .likeRight(MesXslFormulaSpec::getRubberCode, basePrefix); + if (StringUtils.isNotBlank(excludeSpecId)) { + queryWrapper.ne(MesXslFormulaSpec::getId, excludeSpecId); + } + List existingList = this.list(queryWrapper); + Set usedLetters = new HashSet<>(); + for (MesXslFormulaSpec item : existingList) { + if (item == null || StringUtils.isBlank(item.getRubberCode())) { + continue; + } + if (!item.getRubberCode().startsWith(basePrefix) || item.getRubberCode().length() <= basePrefix.length()) { + continue; + } + String suffix = item.getRubberCode().substring(basePrefix.length()); + Matcher matcher = RUBBER_CODE_VERSION_PATTERN.matcher(suffix); + if (matcher.matches()) { + usedLetters.add(matcher.group(1).charAt(0)); + } + } + return usedLetters; + } + //update-end---author:cursor ---date:20260521 for:配合示方胶料代号自动生成 D+胶料名称+分类+版本号----------- + + private void fillMainDefaults(MesXslFormulaSpec main) { + if (StringUtils.isBlank(main.getCategory())) { + //update-begin---author:cursor ---date:20260521 for:配合示方分类字典默认值改为 S----------- + main.setCategory("S"); + //update-end---author:cursor ---date:20260521 for:配合示方分类字典默认值改为 S----------- + } + if (StringUtils.isBlank(main.getStatus())) { + main.setStatus("compile"); + } + if (main.getHasManualBatch() == null) { + main.setHasManualBatch(0); + } + } + + private void insertLines(MesXslFormulaSpec main, List lineList) { + if (CollectionUtils.isEmpty(lineList)) { + return; + } + Date now = new Date(); + int sort = 0; + //update-begin---author:cursor ---date:20260521 for:配合示方明细重量%按PHR/总PHR自动计算----------- + BigDecimal totalPhr = BigDecimal.ZERO; + for (MesXslFormulaSpecLine line : lineList) { + if (line == null || StringUtils.isBlank(line.getMixerMaterialId()) || line.getPhr() == null) { + continue; + } + totalPhr = totalPhr.add(line.getPhr()); + } + if (main.getTotalPhr() == null) { + main.setTotalPhr(totalPhr); + } + BigDecimal weightBase = main.getTotalPhr() != null && main.getTotalPhr().compareTo(BigDecimal.ZERO) > 0 + ? main.getTotalPhr() + : totalPhr; + //update-end---author:cursor ---date:20260521 for:配合示方明细重量%按PHR/总PHR自动计算----------- + boolean hasManual = false; + for (MesXslFormulaSpecLine line : lineList) { + if (line == null || StringUtils.isBlank(line.getMixerMaterialId())) { + continue; + } + line.setId(null); + line.setFormulaSpecId(main.getId()); + line.setSortNo(sort++); + fillMaterialInfo(line); + fillVolumeIfBlank(line); + //update-begin---author:cursor ---date:20260521 for:配合示方明细重量%按PHR/总PHR自动计算----------- + fillWeightPercent(line, weightBase); + //update-end---author:cursor ---date:20260521 for:配合示方明细重量%按PHR/总PHR自动计算----------- + if (line.getCreateTime() == null) { + line.setCreateTime(now); + } + if (line.getUpdateTime() == null) { + line.setUpdateTime(now); + } + if ("manual".equals(line.getWeighMode())) { + hasManual = true; + } + lineMapper.insert(line); + } + if (main.getTotalPhr() == null) { + main.setTotalPhr(totalPhr); + } + if (main.getHasManualBatch() == null || main.getHasManualBatch() == 0) { + main.setHasManualBatch(hasManual ? 1 : 0); + } + } + + private void fillMaterialInfo(MesXslFormulaSpecLine line) { + MesMixerMaterial material = mesMixerMaterialService.getById(line.getMixerMaterialId()); + if (material == null) { + return; + } + line.setMixerMaterialCode(material.getMaterialCode()); + line.setMixerMaterialName(material.getMaterialName()); + if (StringUtils.isBlank(line.getMaterialDesc())) { + line.setMaterialDesc(StringUtils.defaultIfBlank(material.getMaterialDesc(), material.getMaterialName())); + } + } + + private void fillVolumeIfBlank(MesXslFormulaSpecLine line) { + if (line.getVolume() != null || line.getPhr() == null || StringUtils.isBlank(line.getMixerMaterialId())) { + return; + } + MesMixerMaterial material = mesMixerMaterialService.getById(line.getMixerMaterialId()); + if (material == null || material.getSpecificGravity() == null || material.getSpecificGravity().compareTo(BigDecimal.ZERO) <= 0) { + return; + } + line.setVolume(line.getPhr().divide(material.getSpecificGravity(), 6, RoundingMode.HALF_UP)); + } + + private void fillWeightPercent(MesXslFormulaSpecLine line, BigDecimal totalPhr) { + //update-begin---author:cursor ---date:20260521 for:配合示方明细重量%按PHR/总PHR自动计算(可手工覆盖)----------- + if (line.getWeightPercent() != null || line.getPhr() == null || totalPhr == null || totalPhr.compareTo(BigDecimal.ZERO) <= 0) { + return; + } + line.setWeightPercent(line.getPhr().multiply(BigDecimal.valueOf(100)).divide(totalPhr, 4, RoundingMode.HALF_UP)); + //update-end---author:cursor ---date:20260521 for:配合示方明细重量%按PHR/总PHR自动计算(可手工覆盖)----------- + } + + //update-begin---author:cursor ---date:20260521 for:【配合示方】保存后汇总A/Q胶比重写入数据库----------- + /** 根据明细重新汇总主表 TOTAL PHR、A胶TOTAL PHR、比重与人工配料标记 */ + private void refreshMainSummary(String mainId) { + List lines = selectLinesByMainId(mainId); + if (CollectionUtils.isEmpty(lines)) { + return; + } + BigDecimal totalPhr = BigDecimal.ZERO; + BigDecimal aRubberPhr = BigDecimal.ZERO; + BigDecimal aRubberVolume = BigDecimal.ZERO; + BigDecimal qRubberPhr = BigDecimal.ZERO; + BigDecimal qRubberVolume = BigDecimal.ZERO; + BigDecimal naturalRubber = BigDecimal.ZERO; + BigDecimal syntheticRubber = BigDecimal.ZERO; + boolean hasManual = false; + Map materialCache = new HashMap<>(); + Set naturalCategoryIds = mesXslFormulaSpecSettingService.getNaturalMinorCategoryIds(); + Set syntheticCategoryIds = mesXslFormulaSpecSettingService.getSyntheticMinorCategoryIds(); + for (MesXslFormulaSpecLine line : lines) { + if (line == null) { + continue; + } + if (line.getPhr() != null) { + totalPhr = totalPhr.add(line.getPhr()); + if ("A".equals(line.getStep())) { + aRubberPhr = aRubberPhr.add(line.getPhr()); + } else if ("Q".equals(line.getStep())) { + qRubberPhr = qRubberPhr.add(line.getPhr()); + } + } + if ("manual".equals(line.getWeighMode())) { + hasManual = true; + } + BigDecimal volume = resolveLineVolume(line); + if (volume == null) { + continue; + } + if ("A".equals(line.getStep())) { + aRubberVolume = aRubberVolume.add(volume); + } else if ("Q".equals(line.getStep())) { + qRubberVolume = qRubberVolume.add(volume); + } + //update-begin---author:cursor ---date:20260521 for:【配合示方】含胶率按密炼物料小类汇总重量%----------- + if (line.getWeightPercent() != null && StringUtils.isNotBlank(line.getMixerMaterialId())) { + MesMixerMaterial mixerMaterial = materialCache.computeIfAbsent( + line.getMixerMaterialId(), mesMixerMaterialService::getById); + if (mixerMaterial != null && StringUtils.isNotBlank(mixerMaterial.getMinorCategoryId())) { + String minorCategoryId = mixerMaterial.getMinorCategoryId(); + if (!naturalCategoryIds.isEmpty() && naturalCategoryIds.contains(minorCategoryId)) { + naturalRubber = naturalRubber.add(line.getWeightPercent()); + } else if (!syntheticCategoryIds.isEmpty() && syntheticCategoryIds.contains(minorCategoryId)) { + syntheticRubber = syntheticRubber.add(line.getWeightPercent()); + } + } + } + //update-end---author:cursor ---date:20260521 for:【配合示方】含胶率按密炼物料小类汇总重量%----------- + } + //update-begin---author:cursor ---date:20260521 for:【配合示方】STEP全为A/Q时对应胶比重清零并写库----------- + BigDecimal aRubberSg = aRubberVolume.compareTo(BigDecimal.ZERO) > 0 + ? aRubberPhr.divide(aRubberVolume, 6, RoundingMode.HALF_UP) + : null; + BigDecimal qRubberSg = qRubberVolume.compareTo(BigDecimal.ZERO) > 0 + ? qRubberPhr.divide(qRubberVolume, 6, RoundingMode.HALF_UP) + : null; + BigDecimal aRubberTotalPhr = aRubberPhr.compareTo(BigDecimal.ZERO) > 0 ? aRubberPhr : null; + BigDecimal naturalRubberValue = naturalRubber.compareTo(BigDecimal.ZERO) > 0 + ? naturalRubber.setScale(4, RoundingMode.HALF_UP) + : null; + BigDecimal syntheticRubberValue = syntheticRubber.compareTo(BigDecimal.ZERO) > 0 + ? syntheticRubber.setScale(4, RoundingMode.HALF_UP) + : null; + BigDecimal totalAmount = null; + if (naturalRubberValue != null || syntheticRubberValue != null) { + totalAmount = (naturalRubberValue != null ? naturalRubberValue : BigDecimal.ZERO) + .add(syntheticRubberValue != null ? syntheticRubberValue : BigDecimal.ZERO) + .setScale(4, RoundingMode.HALF_UP); + } + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper() + .eq(MesXslFormulaSpec::getId, mainId) + .set(MesXslFormulaSpec::getTotalPhr, totalPhr) + .set(MesXslFormulaSpec::getHasManualBatch, hasManual ? 1 : 0) + .set(MesXslFormulaSpec::getARubberTotalPhr, aRubberTotalPhr) + .set(MesXslFormulaSpec::getARubberSg, aRubberSg) + .set(MesXslFormulaSpec::getQRubberSg, qRubberSg) + .set(MesXslFormulaSpec::getNaturalRubber, naturalRubberValue) + .set(MesXslFormulaSpec::getSyntheticRubber, syntheticRubberValue) + .set(MesXslFormulaSpec::getTotalAmount, totalAmount); + this.update(updateWrapper); + //update-end---author:cursor ---date:20260521 for:【配合示方】STEP全为A/Q时对应胶比重清零并写库----------- + } + + /** 优先取明细已保存体积,缺失时按 PHR/物料比重补算 */ + private BigDecimal resolveLineVolume(MesXslFormulaSpecLine line) { + if (line == null) { + return null; + } + if (line.getVolume() != null && line.getVolume().compareTo(BigDecimal.ZERO) > 0) { + return line.getVolume(); + } + if (line.getPhr() == null || StringUtils.isBlank(line.getMixerMaterialId())) { + return null; + } + MesMixerMaterial material = mesMixerMaterialService.getById(line.getMixerMaterialId()); + if (material == null || material.getSpecificGravity() == null || material.getSpecificGravity().compareTo(BigDecimal.ZERO) <= 0) { + return null; + } + return line.getPhr().divide(material.getSpecificGravity(), 6, RoundingMode.HALF_UP); + } + //update-end---author:cursor ---date:20260521 for:【配合示方】保存后汇总A/Q胶比重写入数据库----------- +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecSettingServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecSettingServiceImpl.java new file mode 100644 index 0000000..dbbc058 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecSettingServiceImpl.java @@ -0,0 +1,104 @@ +package org.jeecg.modules.xslmes.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.jeecg.modules.system.entity.SysCategory; +import org.jeecg.modules.system.service.ISysCategoryService; +import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecSetting; +import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecSettingMapper; +import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecSettingService; +import org.jeecg.modules.xslmes.vo.MesXslFormulaRubberContentSettingVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class MesXslFormulaSpecSettingServiceImpl extends ServiceImpl + implements IMesXslFormulaSpecSettingService { + + private static final String DEFAULT_NATURAL_CATEGORY_CODE = "XSLMES_MATERIAL_RAW_AUX_TRJ"; + private static final String DEFAULT_SYNTHETIC_CATEGORY_CODE = "XSLMES_MATERIAL_RAW_AUX_HCJ"; + + private final ISysCategoryService sysCategoryService; + + public MesXslFormulaSpecSettingServiceImpl(ISysCategoryService sysCategoryService) { + this.sysCategoryService = sysCategoryService; + } + + @Override + public MesXslFormulaRubberContentSettingVO getRubberContentSetting() { + MesXslFormulaSpecSetting setting = loadOrInitSetting(); + MesXslFormulaRubberContentSettingVO vo = new MesXslFormulaRubberContentSettingVO(); + vo.setNaturalMinorCategoryIds(parseIdList(setting.getNaturalMinorCategoryIds())); + vo.setSyntheticMinorCategoryIds(parseIdList(setting.getSyntheticMinorCategoryIds())); + return vo; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveRubberContentSetting(MesXslFormulaRubberContentSettingVO settingVo) { + MesXslFormulaSpecSetting setting = loadOrInitSetting(); + setting.setNaturalMinorCategoryIds(joinIdList(settingVo != null ? settingVo.getNaturalMinorCategoryIds() : null)); + setting.setSyntheticMinorCategoryIds(joinIdList(settingVo != null ? settingVo.getSyntheticMinorCategoryIds() : null)); + setting.setUpdateTime(new Date()); + this.updateById(setting); + } + + @Override + public Set getNaturalMinorCategoryIds() { + return new LinkedHashSet<>(parseIdList(loadOrInitSetting().getNaturalMinorCategoryIds())); + } + + @Override + public Set getSyntheticMinorCategoryIds() { + return new LinkedHashSet<>(parseIdList(loadOrInitSetting().getSyntheticMinorCategoryIds())); + } + + private MesXslFormulaSpecSetting loadOrInitSetting() { + MesXslFormulaSpecSetting setting = this.getById(MesXslFormulaSpecSetting.DEFAULT_ID); + if (setting != null) { + return setting; + } + setting = new MesXslFormulaSpecSetting(); + setting.setId(MesXslFormulaSpecSetting.DEFAULT_ID); + setting.setNaturalMinorCategoryIds(resolveCategoryIdByCode(DEFAULT_NATURAL_CATEGORY_CODE)); + setting.setSyntheticMinorCategoryIds(resolveCategoryIdByCode(DEFAULT_SYNTHETIC_CATEGORY_CODE)); + setting.setCreateTime(new Date()); + this.save(setting); + return setting; + } + + private String resolveCategoryIdByCode(String categoryCode) { + if (StringUtils.isBlank(categoryCode)) { + return null; + } + SysCategory category = sysCategoryService.getOne( + new LambdaQueryWrapper().eq(SysCategory::getCode, categoryCode).last("LIMIT 1")); + return category != null ? category.getId() : null; + } + + private List parseIdList(String raw) { + if (StringUtils.isBlank(raw)) { + return Collections.emptyList(); + } + return Arrays.stream(raw.split(",")) + .map(String::trim) + .filter(StringUtils::isNotBlank) + .distinct() + .collect(Collectors.toList()); + } + + private String joinIdList(List ids) { + if (ids == null || ids.isEmpty()) { + return null; + } + return ids.stream().filter(StringUtils::isNotBlank).map(String::trim).distinct().collect(Collectors.joining(",")); + } +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaRubberContentSettingVO.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaRubberContentSettingVO.java new file mode 100644 index 0000000..f29aa5a --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaRubberContentSettingVO.java @@ -0,0 +1,22 @@ +package org.jeecg.modules.xslmes.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import lombok.Data; + +/** + * 配合示方含胶率物料小类配置 + */ +@Data +@Schema(description = "配合示方含胶率物料小类配置") +public class MesXslFormulaRubberContentSettingVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "天然橡胶物料小类ID列表") + private List naturalMinorCategoryIds = new ArrayList<>(); + + @Schema(description = "合成橡胶物料小类ID列表") + private List syntheticMinorCategoryIds = new ArrayList<>(); +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaSpecPage.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaSpecPage.java new file mode 100644 index 0000000..8df8685 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaSpecPage.java @@ -0,0 +1,10 @@ +package org.jeecg.modules.xslmes.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec; + +/** 配合示方主子保存 VO */ +@Data +@EqualsAndHashCode(callSuper = true) +public class MesXslFormulaSpecPage extends MesXslFormulaSpec {} diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_91__mes_xsl_formula_spec.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_91__mes_xsl_formula_spec.sql new file mode 100644 index 0000000..854db70 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_91__mes_xsl_formula_spec.sql @@ -0,0 +1,186 @@ +-- 配合示方:分类/STEP/称量方式/状态字典 + 主/子表 + 菜单(挂 MES技术管理)+ admin 授权 +SET NAMES utf8mb4; + +INSERT IGNORE INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`) +VALUES ('1995000000000000010', '配合示方分类', 'xslmes_formula_spec_category', 'MES配合示方分类', 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 ('1995000000000001001', '1995000000000000010', '标准', 'standard', 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 ('1995000000000001002', '1995000000000000010', '临时', 'temporary', 2, 1, 'admin', NOW()); + +INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`) +VALUES ('1995000000000001003', '1995000000000000010', '实验', 'trial', 3, 1, 'admin', NOW()); + +INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`) +VALUES ('1995000000000001004', '1995000000000000010', '消费', 'consumption', 4, 1, 'admin', NOW()); + +INSERT IGNORE INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`) +VALUES ('1995000000000000011', '配合示方STEP', 'xslmes_formula_spec_step', 'MES配合示方STEP', 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 ('1995000000000001011', '1995000000000000011', 'A', 'A', 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 ('1995000000000001012', '1995000000000000011', 'B', 'B', 2, 1, 'admin', NOW()); + +INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`) +VALUES ('1995000000000001013', '1995000000000000011', 'Q', 'Q', 3, 1, 'admin', NOW()); + +INSERT IGNORE INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`) +VALUES ('1995000000000000012', '配合示方称量方式', 'xslmes_formula_spec_weigh_mode', 'MES配合示方自动/人工称量', 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 ('1995000000000001021', '1995000000000000012', '自动称量1', 'auto1', 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 ('1995000000000001022', '1995000000000000012', '人工称量', 'manual', 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 ('1995000000000000013', '配合示方状态', 'xslmes_formula_spec_status', 'MES配合示方状态', 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 ('1995000000000001031', '1995000000000000013', '编制', 'compile', 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 ('1995000000000001032', '1995000000000000013', '校对', 'proofread', 2, 1, 'admin', NOW()); + +INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`) +VALUES ('1995000000000001033', '1995000000000000013', '审核', 'audit', 3, 1, 'admin', NOW()); + +INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`) +VALUES ('1995000000000001034', '1995000000000000013', '批准', 'approve', 4, 1, 'admin', NOW()); + +INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`) +VALUES ('1995000000000001035', '1995000000000000013', '正式发布', 'released', 5, 1, 'admin', NOW()); + +INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`) +VALUES ('1995000000000001036', '1995000000000000013', '作废', 'obsolete', 6, 1, 'admin', NOW()); + +CREATE TABLE IF NOT EXISTS `mes_xsl_formula_spec` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `category` varchar(32) DEFAULT 'standard' COMMENT '分类(字典xslmes_formula_spec_category:standard标准 temporary临时 trial实验 consumption消费)', + `spec_code` varchar(100) DEFAULT NULL COMMENT '示方编号', + `rubber_code` varchar(100) DEFAULT NULL COMMENT '胶料代号', + `basic_formula` varchar(100) DEFAULT NULL COMMENT '基本配合', + `issue_date` date DEFAULT NULL COMMENT '发行日期', + `purpose` varchar(500) DEFAULT NULL COMMENT '用途', + `issue_number` varchar(100) DEFAULT NULL COMMENT '发行编号', + `mixing_stages` int DEFAULT NULL COMMENT '混合段数(1-7)', + `mixing_machine` varchar(200) DEFAULT NULL COMMENT '混合机器', + `issue_dept_id` varchar(32) DEFAULT NULL COMMENT '发行部门ID', + `issue_dept_name` varchar(200) DEFAULT NULL COMMENT '发行部门名称冗余', + `a_rubber_total_phr` decimal(18,4) DEFAULT NULL COMMENT 'A胶TOTAL PHR', + `total_phr` decimal(18,4) DEFAULT NULL COMMENT 'TOTAL PHR', + `issue_reason` text COMMENT '发行理由', + `natural_rubber` decimal(18,4) DEFAULT NULL COMMENT '天然橡胶', + `synthetic_rubber` decimal(18,4) DEFAULT NULL COMMENT '合成橡胶', + `total_amount` decimal(18,4) DEFAULT NULL COMMENT '合计', + `weight_unit_price` decimal(18,4) DEFAULT NULL COMMENT '重量单价', + `volume_unit_price` decimal(18,4) DEFAULT NULL COMMENT '体积单价', + `q_rubber_sg` decimal(18,6) DEFAULT NULL COMMENT 'Q胶比重', + `a_rubber_sg` decimal(18,6) DEFAULT NULL COMMENT 'A胶比重', + `has_manual_batch` int DEFAULT 0 COMMENT '是否有人工配料(0否 1是)', + `status` varchar(32) DEFAULT 'compile' COMMENT '状态(字典xslmes_formula_spec_status)', + `proofread_by` varchar(50) DEFAULT NULL COMMENT '校对人', + `proofread_time` datetime DEFAULT NULL COMMENT '校对时间', + `audit_by` varchar(50) DEFAULT NULL COMMENT '审核人', + `audit_time` datetime DEFAULT NULL COMMENT '审核时间', + `approve_by` varchar(50) DEFAULT NULL COMMENT '批准人', + `approve_time` datetime DEFAULT NULL COMMENT '批准时间', + `tenant_id` int DEFAULT NULL COMMENT '租户ID', + `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_mxfs_spec_code` (`spec_code`), + KEY `idx_mxfs_rubber_code` (`rubber_code`), + KEY `idx_mxfs_issue_number` (`issue_number`), + KEY `idx_mxfs_category` (`category`), + KEY `idx_mxfs_status` (`status`), + KEY `idx_mxfs_issue_date` (`issue_date`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES配合示方'; + +CREATE TABLE IF NOT EXISTS `mes_xsl_formula_spec_line` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `formula_spec_id` varchar(32) NOT NULL COMMENT '配合示方主表ID', + `sort_no` int DEFAULT NULL COMMENT '行序号', + `phr` decimal(18,4) DEFAULT NULL COMMENT 'PHR', + `mixer_material_id` varchar(32) DEFAULT NULL COMMENT '密炼物料ID', + `mixer_material_code` varchar(100) DEFAULT NULL COMMENT '密炼物料编码冗余', + `mixer_material_name` varchar(200) DEFAULT NULL COMMENT '密炼物料名称冗余', + `material_desc` varchar(500) DEFAULT NULL COMMENT '物料描述', + `step` varchar(8) DEFAULT NULL COMMENT 'STEP(字典xslmes_formula_spec_step:A/B/Q)', + `weigh_mode` varchar(32) DEFAULT NULL COMMENT '称量方式(字典xslmes_formula_spec_weigh_mode)', + `weight_percent` decimal(18,4) DEFAULT NULL COMMENT '重量%', + `volume` decimal(18,6) DEFAULT NULL COMMENT '体积', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + `stage1` decimal(18,4) DEFAULT NULL COMMENT '混合段1', + `stage2` decimal(18,4) DEFAULT NULL COMMENT '混合段2', + `stage3` decimal(18,4) DEFAULT NULL COMMENT '混合段3', + `stage4` decimal(18,4) DEFAULT NULL COMMENT '混合段4', + `stage5` decimal(18,4) DEFAULT NULL COMMENT '混合段5', + `stage6` decimal(18,4) DEFAULT NULL COMMENT '混合段6', + `stage7` decimal(18,4) DEFAULT NULL COMMENT '混合段7', + `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_mxfsl_formula_spec_id` (`formula_spec_id`), + KEY `idx_mxfsl_mixer_material_id` (`mixer_material_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 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 ( + '177925970995530', '1900000000000000810', '配合示方', '/xslmes/mesXslFormulaSpec', + 'xslmes/mesXslFormulaSpec/MesXslFormulaSpecList', 1, 'MesXslFormulaSpecList', NULL, + 1, NULL, '0', 1.00, 0, 'ant-design:experiment-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 ('177925970995531', '177925970995530', '新增', 2, 'xslmes:mes_xsl_formula_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 ('177925970995532', '177925970995530', '编辑', 2, 'xslmes:mes_xsl_formula_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 ('177925970995533', '177925970995530', '删除', 2, 'xslmes:mes_xsl_formula_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 ('177925970995534', '177925970995530', '批量删除', 2, 'xslmes:mes_xsl_formula_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 ('177925970995535', '177925970995530', '导出', 2, 'xslmes:mes_xsl_formula_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 ('177925970995536', '177925970995530', '导入', 2, 'xslmes:mes_xsl_formula_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 ( + '177925970995530', '177925970995531', '177925970995532', + '177925970995533', '177925970995534', '177925970995535', '177925970995536' + ) + 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_92__mes_xsl_formula_spec_stage_total.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_92__mes_xsl_formula_spec_stage_total.sql new file mode 100644 index 0000000..079adc0 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_92__mes_xsl_formula_spec_stage_total.sql @@ -0,0 +1,9 @@ +-- 配合示方:主表新增混合段1-7合计字段 +ALTER TABLE `mes_xsl_formula_spec` + ADD COLUMN `stage1_total` decimal(18,4) DEFAULT NULL COMMENT '混合段1合计' AFTER `total_phr`, + ADD COLUMN `stage2_total` decimal(18,4) DEFAULT NULL COMMENT '混合段2合计' AFTER `stage1_total`, + ADD COLUMN `stage3_total` decimal(18,4) DEFAULT NULL COMMENT '混合段3合计' AFTER `stage2_total`, + ADD COLUMN `stage4_total` decimal(18,4) DEFAULT NULL COMMENT '混合段4合计' AFTER `stage3_total`, + ADD COLUMN `stage5_total` decimal(18,4) DEFAULT NULL COMMENT '混合段5合计' AFTER `stage4_total`, + ADD COLUMN `stage6_total` decimal(18,4) DEFAULT NULL COMMENT '混合段6合计' AFTER `stage5_total`, + ADD COLUMN `stage7_total` decimal(18,4) DEFAULT NULL COMMENT '混合段7合计' AFTER `stage6_total`; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_93__mes_xsl_formula_spec_category_dict.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_93__mes_xsl_formula_spec_category_dict.sql new file mode 100644 index 0000000..04a9164 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_93__mes_xsl_formula_spec_category_dict.sql @@ -0,0 +1,15 @@ +-- 配合示方分类字典:标准示方 S / 临时示方 P / 试验示方 T / 消费示方 C +SET NAMES utf8mb4; + +UPDATE `sys_dict_item` SET `item_text` = '标准示方', `item_value` = 'S' WHERE `id` = '1995000000000001001'; +UPDATE `sys_dict_item` SET `item_text` = '临时示方', `item_value` = 'P' WHERE `id` = '1995000000000001002'; +UPDATE `sys_dict_item` SET `item_text` = '试验示方', `item_value` = 'T' WHERE `id` = '1995000000000001003'; +UPDATE `sys_dict_item` SET `item_text` = '消费示方', `item_value` = 'C' WHERE `id` = '1995000000000001004'; + +UPDATE `mes_xsl_formula_spec` SET `category` = 'S' WHERE `category` = 'standard'; +UPDATE `mes_xsl_formula_spec` SET `category` = 'P' WHERE `category` = 'temporary'; +UPDATE `mes_xsl_formula_spec` SET `category` = 'T' WHERE `category` = 'trial'; +UPDATE `mes_xsl_formula_spec` SET `category` = 'C' WHERE `category` = 'consumption'; + +ALTER TABLE `mes_xsl_formula_spec` + MODIFY COLUMN `category` varchar(32) DEFAULT 'S' COMMENT '分类(字典xslmes_formula_spec_category:S标准示方 P临时示方 T试验示方 C消费示方)'; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_94__mes_xsl_formula_spec_rubber_material_id.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_94__mes_xsl_formula_spec_rubber_material_id.sql new file mode 100644 index 0000000..98ba786 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_94__mes_xsl_formula_spec_rubber_material_id.sql @@ -0,0 +1,7 @@ +-- 配合示方:关联胶料主数据,支持胶料代号自动生成 +SET NAMES utf8mb4; + +ALTER TABLE `mes_xsl_formula_spec` + ADD COLUMN `rubber_material_id` varchar(32) DEFAULT NULL COMMENT '胶料ID(关联mes_material.id)' AFTER `rubber_code`; + +CREATE INDEX `idx_mxfs_rubber_material_id` ON `mes_xsl_formula_spec` (`rubber_material_id`); diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_95__mes_xsl_formula_spec_step_remove_b.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_95__mes_xsl_formula_spec_step_remove_b.sql new file mode 100644 index 0000000..a9b8cab --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_95__mes_xsl_formula_spec_step_remove_b.sql @@ -0,0 +1,10 @@ +-- 配合示方 STEP 字典:删除字典值 B +SET NAMES utf8mb4; + +-- 已有业务数据若使用 B,清空以便重新选择 +UPDATE `mes_xsl_formula_spec_line` SET `step` = NULL WHERE `step` = 'B'; + +DELETE FROM `sys_dict_item` WHERE `id` = '1995000000000001012'; + +ALTER TABLE `mes_xsl_formula_spec_line` + MODIFY COLUMN `step` varchar(8) DEFAULT NULL COMMENT 'STEP(字典xslmes_formula_spec_step:A/Q)'; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_96__mes_xsl_formula_spec_rubber_content_setting.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_96__mes_xsl_formula_spec_rubber_content_setting.sql new file mode 100644 index 0000000..edd6fac --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_96__mes_xsl_formula_spec_rubber_content_setting.sql @@ -0,0 +1,20 @@ +-- 配合示方:含胶率物料小类配置(天然橡胶 / 合成橡胶) +DROP TABLE IF EXISTS `mes_xsl_formula_spec_setting`; +CREATE TABLE `mes_xsl_formula_spec_setting` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `natural_minor_category_ids` varchar(2000) DEFAULT NULL COMMENT '天然橡胶物料小类ID,逗号分隔', + `synthetic_minor_category_ids` varchar(2000) 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`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配合示方模块配置'; + +INSERT INTO `mes_xsl_formula_spec_setting` (`id`, `natural_minor_category_ids`, `synthetic_minor_category_ids`, `create_time`) +SELECT + '1993000000000000991', + (SELECT `id` FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_TRJ' LIMIT 1), + (SELECT `id` FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_HCJ' LIMIT 1), + NOW() +WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_formula_spec_setting` WHERE `id` = '1993000000000000991'); diff --git a/jeecgboot-vue3/src/views/mes/material/MesMaterial.api.ts b/jeecgboot-vue3/src/views/mes/material/MesMaterial.api.ts index 3703761..256b2c9 100644 --- a/jeecgboot-vue3/src/views/mes/material/MesMaterial.api.ts +++ b/jeecgboot-vue3/src/views/mes/material/MesMaterial.api.ts @@ -9,11 +9,13 @@ enum Api { deleteBatch = '/mes/material/material/deleteBatch', importExcel = '/mes/material/material/importExcel', exportXls = '/mes/material/material/exportXls', + queryById = '/mes/material/material/queryById', } 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 }, { successMessageMode: 'none' }); export const deleteOne = (params, handleSuccess) => defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => handleSuccess()); diff --git a/jeecgboot-vue3/src/views/mes/material/modules/MesMaterialSelectModal.vue b/jeecgboot-vue3/src/views/mes/material/modules/MesMaterialSelectModal.vue new file mode 100644 index 0000000..c2af658 --- /dev/null +++ b/jeecgboot-vue3/src/views/mes/material/modules/MesMaterialSelectModal.vue @@ -0,0 +1,90 @@ + + + diff --git a/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSelectModal.vue b/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSelectModal.vue index 312bdc9..0e72e83 100644 --- a/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSelectModal.vue +++ b/jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSelectModal.vue @@ -85,8 +85,12 @@ emit('select', { mixerMaterialId: row.id, materialName: row.materialName || '', + materialCode: row.materialCode || '', materialDesc: row.materialDesc || '', materialKind: buildKind(row), + minorCategoryId: row.minorCategoryId || '', + majorCategoryText: row.majorCategoryId_dictText || '', + minorCategoryText: row.minorCategoryId_dictText || '', }); closeModal(); } diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts new file mode 100644 index 0000000..cd57ce4 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts @@ -0,0 +1,43 @@ +import { defHttp } from '/@/utils/http/axios'; +import { Modal } from 'ant-design-vue'; + +enum Api { + list = '/xslmes/mesXslFormulaSpec/list', + save = '/xslmes/mesXslFormulaSpec/add', + edit = '/xslmes/mesXslFormulaSpec/edit', + deleteOne = '/xslmes/mesXslFormulaSpec/delete', + deleteBatch = '/xslmes/mesXslFormulaSpec/deleteBatch', + importExcel = '/xslmes/mesXslFormulaSpec/importExcel', + exportXls = '/xslmes/mesXslFormulaSpec/exportXls', + queryById = '/xslmes/mesXslFormulaSpec/queryById', + queryLineList = '/xslmes/mesXslFormulaSpec/queryLineListByMainId', + generateRubberCode = '/xslmes/mesXslFormulaSpec/generateRubberCode', + getRubberContentSetting = '/xslmes/mesXslFormulaSpec/getRubberContentSetting', + saveRubberContentSetting = '/xslmes/mesXslFormulaSpec/saveRubberContentSetting', +} + +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 queryLineListByMainId = (params) => defHttp.get({ url: Api.queryLineList, params }); +export const generateRubberCode = (params) => + defHttp.get({ url: Api.generateRubberCode, params }, { successMessageMode: 'none' }); +export const getRubberContentSetting = () => defHttp.get({ url: Api.getRubberContentSetting }); +export const saveRubberContentSetting = (params) => defHttp.post({ url: Api.saveRubberContentSetting, 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()), + }); +}; + +export const saveOrUpdate = (params, isUpdate) => defHttp.post({ url: isUpdate ? Api.edit : Api.save, params }); diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts new file mode 100644 index 0000000..90bdf7c --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts @@ -0,0 +1,1033 @@ +import { BasicColumn, FormSchema } from '/@/components/Table'; +import { JVxeColumn, JVxeTypes } from '/@/components/jeecg/JVxeTable/types'; +import { buildUUID } from '/@/utils/uuid'; +import { createLocalStorage } from '/@/utils/cache'; +import { loadCategoryData } from '/@/api/common/api'; +import { loadTreeData as loadCategoryTreeRoot } from '/@/views/system/category/category.api'; +import { MATERIAL_CATEGORY_ROOT_CODE } from '/@/views/mes/material/MesMixerMaterialSysCategory.api'; + +const formulaLineColumnStorage = createLocalStorage(); + +/** 明细列隐藏偏好 localStorage 键 */ +export const FORMULA_LINE_COLUMN_CACHE_KEY = 'mes_xsl_formula_spec_line_hidden_columns'; + +/** 不允许隐藏的明细列 */ +export const FORMULA_LINE_LOCKED_COLUMN_KEYS = ['phr', 'mixerMaterialId']; + +export interface FormulaLineColumnSettingItem { + key: string; + title: string; + locked?: boolean; +} + +const colHalf = { span: 12 }; +const colThird = { span: 8 }; +const colQuarter = { span: 6 }; + +/** 汇总区隐藏字段(明细表 footer 行录入,表单仅承载数据) */ +export const summaryFooterHiddenFields: FormSchema[] = [ + { field: 'aRubberTotalPhr', label: '', component: 'InputNumber', show: false }, + { field: 'totalPhr', label: '', component: 'InputNumber', show: false }, + ...Array.from({ length: 7 }, (_, index) => ({ + field: `stage${index + 1}Total`, + label: '', + component: 'InputNumber', + show: false, + })), +]; + +export const SUMMARY_FOOTER_FIELD_KEYS = [ + 'aRubberTotalPhr', + 'totalPhr', + 'stage1Total', + 'stage2Total', + 'stage3Total', + 'stage4Total', + 'stage5Total', + 'stage6Total', + 'stage7Total', +] as const; + +export const SUMMARY_METRICS_FIELD_KEYS = [ + 'naturalRubber', + 'syntheticRubber', + 'totalAmount', + 'weightUnitPrice', + 'volumeUnitPrice', + 'qRubberSg', + 'aRubberSg', +] as const; + +/** 汇总指标隐藏字段(自定义表格录入,表单仅承载数据) */ +export const summaryMetricsHiddenFields: FormSchema[] = SUMMARY_METRICS_FIELD_KEYS.map((field) => ({ + field, + label: '', + component: 'InputNumber', + show: false, +})); + +export const stageTotalNumberProps = { + min: 0, + precision: 4, + style: { width: '100%' }, + bordered: false, + controls: false, +}; + +export const summaryMetricNumberProps = { + min: 0, + precision: 4, + style: { width: '100%' }, + bordered: false, + controls: false, +}; + +export const summarySgNumberProps = { + min: 0, + precision: 6, + style: { width: '100%' }, + bordered: false, + controls: false, +}; + +/** 明细行 PHR 合计(作为重量%计算的分母) */ +export function calcTotalPhrFromLines(lines: Recordable[]): number | null { + const sum = (lines || []).reduce((acc, row) => { + const value = Number(row?.phr); + return acc + (Number.isFinite(value) ? value : 0); + }, 0); + return sum > 0 ? Number(sum.toFixed(4)) : null; +} + +/** 按 单条PHR / 总PHR × 100 回填各行重量% */ +export function applyWeightPercentToLines(lines: Recordable[]): void { + const totalPhr = calcTotalPhrFromLines(lines); + (lines || []).forEach((row) => { + if (!row) { + return; + } + const phr = Number(row.phr); + if (!Number.isFinite(phr) || totalPhr == null || totalPhr <= 0) { + row.weightPercent = null; + return; + } + row.weightPercent = Number(((phr / totalPhr) * 100).toFixed(1)); + }); +} + +/** STEP=A 的 PHR 合计(A胶 TOTAL PHR) */ +export function calcARubberTotalPhrFromLines(lines: Recordable[]): number | null { + const sum = (lines || []).reduce((acc, row) => { + if (row?.step !== 'A') { + return acc; + } + const value = Number(row?.phr); + return acc + (Number.isFinite(value) ? value : 0); + }, 0); + return sum > 0 ? Number(sum.toFixed(4)) : null; +} + +/** + * 混合段累计合计(仅统计可编辑段数): + * stage1Total=列1总和,stage2Total=列1+列2,…;超出混合段数的框置空。 + */ +export function calcStageTotalsFromLines(lines: Recordable[], mixingStages?: number | string | null): Recordable { + const totals: Recordable = {}; + const stageCount = getActiveStageCount(mixingStages); + + for (let i = 1; i <= 7; i++) { + totals[`stage${i}Total`] = null; + } + if (stageCount <= 0) { + return totals; + } + + const colSums: number[] = []; + for (let i = 1; i <= stageCount; i++) { + const key = `stage${i}`; + const sum = (lines || []).reduce((acc, row) => { + const value = Number(row?.[key]); + return acc + (Number.isFinite(value) ? value : 0); + }, 0); + colSums.push(sum); + } + + let cumulative = 0; + for (let i = 1; i <= stageCount; i++) { + cumulative += colSums[i - 1]; + totals[`stage${i}Total`] = cumulative > 0 ? Number(cumulative.toFixed(4)) : null; + } + return totals; +} + +/** 底部汇总区:A胶 TOTAL PHR、TOTAL PHR、混合段 1..N 累计合计(N=混合段数) */ +export function calcFooterSummaryFromLines(lines: Recordable[], mixingStages?: number | string | null): Recordable { + return { + aRubberTotalPhr: calcARubberTotalPhrFromLines(lines), + totalPhr: calcTotalPhrFromLines(lines), + ...calcStageTotalsFromLines(lines, mixingStages), + }; +} + +/** 明细行有效体积(优先使用已计算的 volume) */ +function getLineVolumeValue(row: Recordable): number | null { + const volume = Number(row?.volume); + return Number.isFinite(volume) && volume > 0 ? volume : null; +} + +/** + * A胶比重 = STEP=A 各行 PHR 合计 ÷ STEP=A 各行体积合计 + * 单行体积 = PHR ÷ 物料比重 + */ +export function calcARubberSgFromLines(lines: Recordable[]): number | null { + let totalPhr = 0; + let totalVolume = 0; + (lines || []).forEach((row) => { + if (row?.step !== 'A') { + return; + } + const phr = Number(row?.phr); + const volume = getLineVolumeValue(row); + if (!Number.isFinite(phr) || phr <= 0 || volume == null) { + return; + } + totalPhr += phr; + totalVolume += volume; + }); + if (totalPhr <= 0 || totalVolume <= 0) { + return null; + } + return Number((totalPhr / totalVolume).toFixed(6)); +} + +/** + * Q胶比重 = STEP=Q 各行 PHR 合计 ÷ STEP=Q 各行体积合计 + * 单行体积 = PHR ÷ 物料比重 + */ +export function calcQRubberSgFromLines(lines: Recordable[]): number | null { + let totalPhr = 0; + let totalVolume = 0; + (lines || []).forEach((row) => { + if (row?.step !== 'Q') { + return; + } + const phr = Number(row?.phr); + const volume = getLineVolumeValue(row); + if (!Number.isFinite(phr) || phr <= 0 || volume == null) { + return; + } + totalPhr += phr; + totalVolume += volume; + }); + if (totalPhr <= 0 || totalVolume <= 0) { + return null; + } + return Number((totalPhr / totalVolume).toFixed(6)); +} + +/** 默认物料小类编码(仅作初始配置参考) */ +export const MIXER_MINOR_CATEGORY_CODE = { + NATURAL_RUBBER: 'XSLMES_MATERIAL_RAW_AUX_TRJ', + SYNTHETIC_RUBBER: 'XSLMES_MATERIAL_RAW_AUX_HCJ', +} as const; + +export type RubberContentSetting = { + naturalMinorCategoryIds: string[]; + syntheticMinorCategoryIds: string[]; +}; + +export const EMPTY_RUBBER_CONTENT_SETTING: RubberContentSetting = { + naturalMinorCategoryIds: [], + syntheticMinorCategoryIds: [], +}; + +/** 将 MES物料分类 树递归展开为下拉选项(含大类、小类等全部节点) */ +function flattenMaterialCategoryTreeToOptions( + nodes: Recordable[], + parentLabel = '', +): Array<{ label: string; value: string }> { + const options: Array<{ label: string; value: string }> = []; + (nodes || []).forEach((node) => { + const id = String(node?.key ?? node?.id ?? node?.value ?? ''); + const name = String(node?.title ?? node?.name ?? node?.text ?? ''); + if (!id || !name) { + return; + } + const label = parentLabel ? `${parentLabel} / ${name}` : name; + options.push({ label, value: id }); + const children = (node?.children as Recordable[]) || []; + if (children.length) { + options.push(...flattenMaterialCategoryTreeToOptions(children, label)); + } + }); + return options; +} + +/** 一次性加载 MES物料分类 全部节点,供含胶率设置手动多选 */ +export async function fetchMaterialCategoryOptions(): Promise> { + try { + const list = await loadCategoryData({ code: MATERIAL_CATEGORY_ROOT_CODE }); + const rows = Array.isArray(list) ? list : []; + if (rows.length) { + return rows + .map((item: Recordable) => ({ + label: String(item?.text ?? item?.label ?? item?.title ?? item?.name ?? ''), + value: String(item?.value ?? item?.id ?? item?.key ?? ''), + })) + .filter((item) => item.value && item.label); + } + } catch { + // 回退到与密炼物料页一致的分类树加载 + } + const treeRaw = await loadCategoryTreeRoot({ async: false, pcode: MATERIAL_CATEGORY_ROOT_CODE }); + const tree = Array.isArray(treeRaw) ? treeRaw : []; + return flattenMaterialCategoryTreeToOptions(tree); +} + +/** @deprecated 请使用 fetchMaterialCategoryOptions */ +export const fetchMixerMinorCategoryOptions = fetchMaterialCategoryOptions; + +/** 汇总区比重指标:Q胶比重、A胶比重 */ +export function calcRubberSgMetricsFromLines(lines: Recordable[]): Recordable { + return { + qRubberSg: calcQRubberSgFromLines(lines), + aRubberSg: calcARubberSgFromLines(lines), + }; +} + +/** + * 含胶率:天然橡胶 / 合成橡胶 = 对应小类密炼物料的重量%之和,合计为两者之和 + */ +export function calcRubberContentMetricsFromLines( + lines: Recordable[], + naturalMinorCategoryIds?: string[] | null, + syntheticMinorCategoryIds?: string[] | null, +): Recordable { + const naturalIdSet = new Set((naturalMinorCategoryIds || []).filter(Boolean)); + const syntheticIdSet = new Set((syntheticMinorCategoryIds || []).filter(Boolean)); + let naturalRubber = 0; + let syntheticRubber = 0; + let hasNatural = false; + let hasSynthetic = false; + (lines || []).forEach((row) => { + if (!row?.mixerMinorCategoryId) { + return; + } + const weightPercent = Number(row?.weightPercent); + if (!Number.isFinite(weightPercent)) { + return; + } + if (naturalIdSet.has(row.mixerMinorCategoryId)) { + naturalRubber += weightPercent; + hasNatural = true; + } else if (syntheticIdSet.has(row.mixerMinorCategoryId)) { + syntheticRubber += weightPercent; + hasSynthetic = true; + } + }); + const naturalValue = hasNatural ? Number(naturalRubber.toFixed(4)) : null; + const syntheticValue = hasSynthetic ? Number(syntheticRubber.toFixed(4)) : null; + const totalAmount = + naturalValue != null || syntheticValue != null + ? Number(((naturalValue ?? 0) + (syntheticValue ?? 0)).toFixed(4)) + : null; + return { + naturalRubber: naturalValue, + syntheticRubber: syntheticValue, + totalAmount, + }; +} + +/** 明细行仅前端展示字段(不落库) */ +export const FORMULA_LINE_DISPLAY_FIELDS = ['mixerMajorCategoryText', 'mixerMinorCategoryText', 'mixerMinorCategoryId'] as const; + +/** 写入密炼物料关联的大类/小类展示文本 */ +export function applyMixerCategoryDisplay(row: Recordable, material?: Recordable | null) { + if (!row) { + return; + } + if (!material) { + row.mixerMajorCategoryText = ''; + row.mixerMinorCategoryText = ''; + row.mixerMinorCategoryId = null; + return; + } + row.mixerMajorCategoryText = material.majorCategoryId_dictText || material.majorCategoryText || ''; + row.mixerMinorCategoryText = material.minorCategoryId_dictText || material.minorCategoryText || ''; + row.mixerMinorCategoryId = material.minorCategoryId || null; +} + +let materialCategoryNameCache: Map | null = null; + +async function getMaterialCategoryNameCache(): Promise> { + if (materialCategoryNameCache) { + return materialCategoryNameCache; + } + try { + const list = await loadCategoryData({ code: MATERIAL_CATEGORY_ROOT_CODE }); + const rows = Array.isArray(list) ? list : []; + materialCategoryNameCache = new Map( + rows + .map((item: Recordable) => [String(item?.value ?? item?.id ?? ''), String(item?.text ?? item?.label ?? '')] as const) + .filter(([id, name]) => id && name), + ); + } catch { + materialCategoryNameCache = new Map(); + } + return materialCategoryNameCache; +} + +/** 关联查询并补全大类/小类展示(queryById 无 dictText 时回退分类字典) */ +export async function hydrateMixerCategoryDisplay(row: Recordable, material?: Recordable | null) { + applyMixerMaterialMeta(row, material); + if (!row || !material) { + return; + } + const needMajor = !row.mixerMajorCategoryText && material.majorCategoryId; + const needMinor = !row.mixerMinorCategoryText && material.minorCategoryId; + if (!needMajor && !needMinor) { + return; + } + const cache = await getMaterialCategoryNameCache(); + if (needMajor) { + row.mixerMajorCategoryText = cache.get(String(material.majorCategoryId)) || ''; + } + if (needMinor) { + row.mixerMinorCategoryText = cache.get(String(material.minorCategoryId)) || ''; + } +} + +/** 选择配合剂后回填物料关联信息(含大类/小类展示) */ +export function applyMixerMaterialMeta(row: Recordable, material?: Recordable | null) { + if (!row) { + return; + } + if (!material) { + row.mixerMaterialName = ''; + row.mixerMaterialCode = ''; + applyMixerCategoryDisplay(row, null); + return; + } + row.mixerMaterialName = material.materialName || row.mixerMaterialName || ''; + row.mixerMaterialCode = material.materialCode || row.mixerMaterialCode || ''; + applyMixerCategoryDisplay(row, material); + if (!row.materialDesc) { + row.materialDesc = material.materialDesc || material.materialName || ''; + } +} + +/** 提交前剔除明细行展示字段 */ +export function stripFormulaLineDisplayFields(line: Recordable) { + const { mixerMajorCategoryText, mixerMinorCategoryText, mixerMinorCategoryId, ...rest } = line; + return rest; +} + +/** 明细表默认空行数(参照原系统约 20 行) */ +export const DEFAULT_LINE_ROW_COUNT = 20; + +export function createEmptyLineRows(count = DEFAULT_LINE_ROW_COUNT): Recordable[] { + return Array.from({ length: count }, () => ({ id: buildUUID() })); +} + +/** 确保每行有唯一 id(JVxeTable rowKey 依赖 id,否则单元格无法渲染) */ +export function normalizeLineRows(rows: Recordable[]): Recordable[] { + return (rows || []).map((r) => ({ ...r, id: r?.id || buildUUID() })); +} + +function sectionTitle(label: string, field: string): FormSchema { + return { + field, + label, + component: 'Divider', + componentProps: { orientation: 'left', plain: false }, + colProps: { span: 24 }, + }; +} + +const hasWorkflowInfo = ({ values }) => + !!(values.proofreadBy || values.proofreadTime || values.auditBy || values.auditTime || values.approveBy || values.approveTime); + +export const columns: BasicColumn[] = [ + { title: '示方编号', align: 'center', dataIndex: 'specCode', width: 150, fixed: 'left' }, + { title: '发行编号', align: 'center', dataIndex: 'issueNumber', width: 140 }, + { title: '胶料代号', align: 'center', dataIndex: 'rubberCode', width: 140 }, + { title: '分类', align: 'center', dataIndex: 'category_dictText', width: 80 }, + { title: '用途', align: 'center', dataIndex: 'purpose', width: 120, ellipsis: true }, + { + title: '人工配料', + align: 'center', + dataIndex: 'hasManualBatch', + width: 90, + customRender: ({ text }) => (text === 1 ? '是' : '否'), + }, + { title: '发行日期', align: 'center', dataIndex: 'issueDate', width: 110 }, + { + title: '制定人', + align: 'center', + dataIndex: 'createBy', + width: 100, + customRender: ({ record }) => record?.createBy_dictText || record?.createBy || '', + }, + { title: '审核人', align: 'center', dataIndex: 'auditBy', width: 100, defaultHidden: true }, + { title: '批准人', align: 'center', dataIndex: 'approveBy', width: 100, defaultHidden: true }, + { title: '状态', align: 'center', dataIndex: 'status_dictText', width: 120 }, + { title: '混合段数', align: 'center', dataIndex: 'mixingStages', width: 90, defaultHidden: true }, + { title: 'TOTAL PHR', align: 'center', dataIndex: 'totalPhr', width: 100, defaultHidden: true }, + { title: '修改时间', align: 'center', dataIndex: 'updateTime', width: 165 }, +]; + +export const searchFormSchema: FormSchema[] = [ + { label: '关键字', field: 'keyword', component: 'Input', colProps: { span: 6 }, componentProps: { placeholder: '示方编号/胶料代号/发行编号/用途' } }, + { + label: '分类', + field: 'category', + component: 'JDictSelectTag', + componentProps: { dictCode: 'xslmes_formula_spec_category', placeholder: '请选择分类' }, + colProps: { span: 6 }, + }, + { + label: '状态', + field: 'status', + component: 'JDictSelectTag', + componentProps: { dictCode: 'xslmes_formula_spec_status', placeholder: '请选择状态' }, + colProps: { span: 6 }, + }, + { + label: '发行日期起', + field: 'issueDate_begin', + component: 'DatePicker', + componentProps: { valueFormat: 'YYYY-MM-DD', placeholder: '开始日期' }, + colProps: { span: 6 }, + }, + { + label: '发行日期止', + field: 'issueDate_end', + component: 'DatePicker', + componentProps: { valueFormat: 'YYYY-MM-DD', placeholder: '结束日期' }, + colProps: { span: 6 }, + }, +]; + +/** 基本信息(顶部) */ +export const basicFormSchema: FormSchema[] = [ + { label: '', field: 'id', component: 'Input', show: false }, + { + label: '分类', + field: 'category', + component: 'JDictSelectTag', + defaultValue: 'S', + show: false, + componentProps: { dictCode: 'xslmes_formula_spec_category', type: 'radioButton' }, + colProps: { span: 24 }, + }, + { + label: '示方编号', + field: 'specCode', + component: 'Input', + show: false, + dynamicRules: () => [{ required: true, message: '请选择胶料并生成示方编号' }], + }, + { + label: '胶料代号', + field: 'rubberCode', + component: 'Input', + show: false, + dynamicRules: () => [{ required: true, message: '请选择胶料并生成胶料代号' }], + }, + { + label: '', + field: 'rubberMaterialId', + component: 'Input', + show: false, + }, + { + label: '基本配合', + field: 'basicFormula', + component: 'Input', + show: false, + }, + { + label: '发行日期', + field: 'issueDate', + component: 'Input', + show: false, + }, + { + label: '发行编号', + field: 'issueNumber', + component: 'Input', + show: false, + }, + { + label: '用途', + field: 'purpose', + component: 'Input', + show: false, + }, + { + label: '混合段数', + field: 'mixingStages', + component: 'InputNumber', + show: false, + }, + { + label: '混合机器', + field: 'mixingMachine', + component: 'Input', + show: false, + }, + { + label: '发行部门', + field: 'issueDeptName', + component: 'Input', + show: false, + }, + { + label: '', + field: 'issueDeptId', + component: 'Input', + show: false, + }, + { + label: '状态', + field: 'status', + component: 'JDictSelectTag', + defaultValue: 'compile', + show: false, + componentProps: { dictCode: 'xslmes_formula_spec_status', disabled: true }, + colProps: colThird, + }, +]; + +/** 汇总信息(底部,参照原配合施工表布局) */ +export const summaryFormSchema: FormSchema[] = [ + ...summaryFooterHiddenFields, + ...summaryMetricsHiddenFields, + { + label: '发行理由', + field: 'issueReason', + component: 'InputTextArea', + colProps: { span: 24 }, + componentProps: { rows: 2, placeholder: '请输入发行理由', maxlength: 1000, showCount: true, bordered: false }, + }, +]; + +/** 审批记录(详情时展示) */ +export const workflowFormSchema: FormSchema[] = [ + sectionTitle('审批记录', 'dividerWorkflow'), + { + label: '校对人', + field: 'proofreadBy', + component: 'Input', + componentProps: { disabled: true, bordered: false }, + colProps: colHalf, + ifShow: ({ values }) => !!values.proofreadBy, + }, + { + label: '校对时间', + field: 'proofreadTime', + component: 'Input', + componentProps: { disabled: true, bordered: false }, + colProps: colHalf, + ifShow: ({ values }) => !!values.proofreadTime, + }, + { + label: '审核人', + field: 'auditBy', + component: 'Input', + componentProps: { disabled: true, bordered: false }, + colProps: colHalf, + ifShow: ({ values }) => !!values.auditBy, + }, + { + label: '审核时间', + field: 'auditTime', + component: 'Input', + componentProps: { disabled: true, bordered: false }, + colProps: colHalf, + ifShow: ({ values }) => !!values.auditTime, + }, + { + label: '批准人', + field: 'approveBy', + component: 'Input', + componentProps: { disabled: true, bordered: false }, + colProps: colHalf, + ifShow: ({ values }) => !!values.approveBy, + }, + { + label: '批准时间', + field: 'approveTime', + component: 'Input', + componentProps: { disabled: true, bordered: false }, + colProps: colHalf, + ifShow: ({ values }) => !!values.approveTime, + }, +]; + +/** 有效混合段数(1-7),未配置时返回 0 */ +export function getActiveStageCount(mixingStages?: number | string | null): number { + if (mixingStages == null || mixingStages === '') { + return 0; + } + const n = Number(mixingStages); + if (Number.isNaN(n) || n <= 0) { + return 0; + } + return Math.min(Math.max(Math.floor(n), 1), 7); +} + +/** + * STEP=A:PHR 写入第 1 混合段;STEP=Q:PHR 写入当前混合段数的最后一列。 + * 返回需写回表格的 stage1-stage7 补丁;非 A/Q 或无可编辑段时返回 null。 + */ +export function buildStepStageValues(row: Recordable, mixingStages?: number | null): Recordable | null { + const step = row?.step; + if (step !== 'A' && step !== 'Q') { + return null; + } + const stageCount = getActiveStageCount(mixingStages); + if (stageCount <= 0) { + return null; + } + const phrRaw = row?.phr; + const phr = + phrRaw != null && phrRaw !== '' && Number.isFinite(Number(phrRaw)) ? Number(phrRaw) : null; + const targetStage = step === 'A' ? 1 : stageCount; + const patch: Recordable = {}; + for (let i = 1; i <= 7; i++) { + patch[`stage${i}`] = i === targetStage ? phr : null; + } + return patch; +} + +/** 将 STEP 规则应用到行对象(就地修改) */ +export function applyStepPhrToLineRow(row: Recordable, mixingStages?: number | null): Recordable | null { + const patch = buildStepStageValues(row, mixingStages); + if (!patch) { + return null; + } + Object.assign(row, patch); + return patch; +} + +/** 解析行 PHR(无效时返回 null) */ +export function getLinePhrValue(row: Recordable): number | null { + const phr = Number(row?.phr); + return Number.isFinite(phr) && phr > 0 ? phr : null; +} + +/** 可编辑混合段列合计(仅统计 1..stageCount) */ +export function calcLineActiveStageSum(row: Recordable, stageCount: number): number { + let sum = 0; + for (let i = 1; i <= stageCount; i++) { + const v = Number(row[`stage${i}`]); + if (Number.isFinite(v)) { + sum += v; + } + } + return sum; +} + +/** 混合段合计超过 PHR 时,扣减当前编辑列 */ +export function clampStageToPhr(row: Recordable, stageCount: number, editedKey: string): number | null { + const phr = getLinePhrValue(row); + if (phr == null || stageCount <= 0) { + return null; + } + const total = calcLineActiveStageSum(row, stageCount); + if (total <= phr) { + return null; + } + const current = Number(row[editedKey]); + if (!Number.isFinite(current)) { + return null; + } + const clamped = Math.max(0, Number((current - (total - phr)).toFixed(4))); + row[editedKey] = clamped; + return clamped; +} + +/** STEP=A:手动编辑 2..N 列时,第 1 列 = PHR − 其余可编辑段之和 */ +export function balanceStepAStages(row: Recordable, stageCount: number, editedKey?: string): Recordable { + const patch: Recordable = {}; + if (editedKey === 'stage1') { + return patch; + } + const phr = getLinePhrValue(row); + if (phr == null || stageCount <= 0) { + return patch; + } + let otherSum = 0; + for (let i = 2; i <= stageCount; i++) { + const v = Number(row[`stage${i}`]); + if (Number.isFinite(v)) { + otherSum += v; + } + } + const stage1 = Math.max(0, Number((phr - otherSum).toFixed(4))); + const next = otherSum > 0 ? stage1 : phr; + if (Number(row.stage1) !== next) { + row.stage1 = next; + patch.stage1 = next; + } + return patch; +} + +/** STEP=Q:手动编辑非末列时,末列 = PHR − 其余可编辑段之和 */ +export function balanceStepQStages(row: Recordable, stageCount: number, editedKey?: string): Recordable { + const patch: Recordable = {}; + const phr = getLinePhrValue(row); + if (phr == null || stageCount <= 0) { + return patch; + } + const lastKey = `stage${stageCount}`; + if (editedKey === lastKey) { + return patch; + } + let otherSum = 0; + for (let i = 1; i < stageCount; i++) { + const v = Number(row[`stage${i}`]); + if (Number.isFinite(v)) { + otherSum += v; + } + } + const lastVal = Math.max(0, Number((phr - otherSum).toFixed(4))); + const next = otherSum > 0 ? lastVal : phr; + if (Number(row[lastKey]) !== next) { + row[lastKey] = next; + patch[lastKey] = next; + } + return patch; +} + +/** + * 混合段单元格编辑后:合计不超过 PHR;STEP=A/Q 自动平衡锚定列。 + * STEP=A 编辑 2..N 列、STEP=Q 编辑非末列时:先扣减锚定列,再判断是否需截断当前列。 + */ +export function processStageCellEdit( + row: Recordable, + editedKey: string, + mixingStages?: number | string | null +): { patch: Recordable; exceeded: boolean; needPhr: boolean } { + const patch: Recordable = {}; + const stageCount = getActiveStageCount(mixingStages); + if (stageCount <= 0 || !/^stage\d+$/.test(editedKey)) { + return { patch, exceeded: false, needPhr: false }; + } + const phr = getLinePhrValue(row); + if (phr == null) { + return { patch, exceeded: false, needPhr: true }; + } + + const lastKey = `stage${stageCount}`; + let exceeded = false; + + const mergePatch = (p: Recordable) => { + Object.keys(p).forEach((k) => { + patch[k] = p[k]; + }); + }; + + // STEP=A:编辑第 2..N 列时先从第 1 列扣减,避免误把当前列截断为 0 + if (row.step === 'A' && editedKey !== 'stage1') { + mergePatch(balanceStepAStages(row, stageCount, editedKey)); + const clamped = clampStageToPhr(row, stageCount, editedKey); + if (clamped != null) { + patch[editedKey] = clamped; + exceeded = true; + mergePatch(balanceStepAStages(row, stageCount, editedKey)); + } + return { patch, exceeded, needPhr: false }; + } + + // STEP=Q:编辑非末列时先从末列扣减 + if (row.step === 'Q' && editedKey !== lastKey) { + mergePatch(balanceStepQStages(row, stageCount, editedKey)); + const clamped = clampStageToPhr(row, stageCount, editedKey); + if (clamped != null) { + patch[editedKey] = clamped; + exceeded = true; + mergePatch(balanceStepQStages(row, stageCount, editedKey)); + } + return { patch, exceeded, needPhr: false }; + } + + // 编辑锚定列或无 STEP:仅截断当前列 + const clamped = clampStageToPhr(row, stageCount, editedKey); + if (clamped != null) { + patch[editedKey] = clamped; + exceeded = true; + } + + return { patch, exceeded, needPhr: false }; +} + +/** 根据混合段数动态生成明细列(1-7 段列按混合段数控制可编辑;未填混合段数时全部禁用) */ +export function buildLineJVxeColumns(mixingStages?: number | null, tableDisabled = false): JVxeColumn[] { + const stageCount = getActiveStageCount(mixingStages); + const hasStages = stageCount > 0; + + const baseCols: JVxeColumn[] = [ + { + title: 'PHR', + key: 'phr', + type: JVxeTypes.inputNumber, + minWidth: 90, + align: 'center', + }, + { + title: '配合剂', + key: 'mixerMaterialId', + type: JVxeTypes.slot, + slotName: 'mixerMaterialSlot', + minWidth: 200, + }, + { + title: '物料大类', + key: 'mixerMajorCategoryText', + type: JVxeTypes.normal, + minWidth: 110, + align: 'center', + }, + { + title: '物料小类', + key: 'mixerMinorCategoryText', + type: JVxeTypes.normal, + minWidth: 110, + align: 'center', + }, + { + title: '物料描述', + key: 'materialDesc', + type: JVxeTypes.input, + minWidth: 160, + }, + { + title: 'STEP', + key: 'step', + type: JVxeTypes.select, + minWidth: 80, + align: 'center', + dictCode: 'xslmes_formula_spec_step', + }, + { + title: '自动/人工', + key: 'weighMode', + type: JVxeTypes.select, + minWidth: 110, + align: 'center', + dictCode: 'xslmes_formula_spec_weigh_mode', + }, + { + title: '重量%', + key: 'weightPercent', + type: JVxeTypes.inputNumber, + minWidth: 90, + align: 'center', + }, + { + title: '体积', + key: 'volume', + type: JVxeTypes.inputNumber, + minWidth: 90, + align: 'center', + placeholder: '自动计算', + }, + { + title: '备注', + key: 'remark', + type: JVxeTypes.input, + minWidth: 80, + }, + ]; + + for (let i = 1; i <= 7; i++) { + const stageNo = i; + const stageDisabled = tableDisabled || !hasStages || stageNo > stageCount; + baseCols.push({ + title: String(i), + key: `stage${i}`, + type: JVxeTypes.inputNumber, + minWidth: 56, + align: 'center', + disabled: stageDisabled, + className: stageDisabled ? 'formula-stage-cell-disabled' : '', + headerClassName: stageDisabled ? 'formula-stage-header-disabled' : '', + props: { + isDisabledCell: () => stageDisabled, + }, + }); + } + return baseCols; +} + +/** 明细列设置项(1-7 段列固定展示在设置列表中) */ +export function getFormulaLineColumnSettingItems(): FormulaLineColumnSettingItem[] { + return buildLineJVxeColumns(null, false).map((col) => ({ + key: String(col.key), + title: String(col.title), + locked: FORMULA_LINE_LOCKED_COLUMN_KEYS.includes(String(col.key)), + })); +} + +/** 读取已隐藏的明细列 key */ +export function loadFormulaLineHiddenColumnKeys(): string[] { + const saved = formulaLineColumnStorage.get(FORMULA_LINE_COLUMN_CACHE_KEY); + if (!Array.isArray(saved)) { + return []; + } + const validKeys = new Set(getFormulaLineColumnSettingItems().map((item) => item.key)); + return saved.filter( + (key) => typeof key === 'string' && !FORMULA_LINE_LOCKED_COLUMN_KEYS.includes(key) && validKeys.has(key), + ); +} + +/** 保存已隐藏的明细列 key */ +export function saveFormulaLineHiddenColumnKeys(hiddenKeys: string[]) { + const validKeys = hiddenKeys.filter((key) => !FORMULA_LINE_LOCKED_COLUMN_KEYS.includes(key)); + if (validKeys.length) { + formulaLineColumnStorage.set(FORMULA_LINE_COLUMN_CACHE_KEY, validKeys); + return; + } + formulaLineColumnStorage.remove(FORMULA_LINE_COLUMN_CACHE_KEY); +} + +/** 按隐藏配置过滤明细列 */ +export function applyFormulaLineColumnVisibility(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))); +} + +/** 审批进度操作人展示:优先字典翻译姓名,其次当前登录用户匹配用户名时取 realname */ +export function resolveFormulaSpecUserDisplayName( + username?: string | null, + dictText?: string | null, + fallbackUser?: { username?: string; realname?: string }, +) { + if (dictText != null && dictText !== '') { + return String(dictText); + } + const user = fallbackUser || {}; + if (username != null && username !== '') { + const name = String(username); + if (user.username && name === user.username && user.realname) { + return user.realname; + } + return name; + } + return user.realname || user.username || ''; +} + +export const superQuerySchema = { + specCode: { title: '示方编号', order: 0, view: 'text' }, + rubberCode: { title: '胶料代号', order: 1, view: 'text' }, + issueNumber: { title: '发行编号', order: 2, view: 'text' }, + category: { title: '分类', order: 3, view: 'list', dictCode: 'xslmes_formula_spec_category' }, + purpose: { title: '用途', order: 4, view: 'text' }, + status: { title: '状态', order: 5, view: 'list', dictCode: 'xslmes_formula_spec_status' }, + issueDate: { title: '发行日期', order: 6, view: 'date' }, +}; diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpecList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpecList.vue new file mode 100644 index 0000000..1e000e9 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpecList.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaLineColumnSetting.vue b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaLineColumnSetting.vue new file mode 100644 index 0000000..f13f0ea --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaLineColumnSetting.vue @@ -0,0 +1,168 @@ + + + + + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaRubberContentSettingModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaRubberContentSettingModal.vue new file mode 100644 index 0000000..6c447e8 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaRubberContentSettingModal.vue @@ -0,0 +1,240 @@ + + + + + + + + + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue new file mode 100644 index 0000000..3cdf834 --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue @@ -0,0 +1,2318 @@ + + + + + + + diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixerPsCompile/MesXslMixerPsCompile.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslMixerPsCompile/MesXslMixerPsCompile.data.ts index f140f7a..753a1f3 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslMixerPsCompile/MesXslMixerPsCompile.data.ts +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixerPsCompile/MesXslMixerPsCompile.data.ts @@ -145,7 +145,6 @@ export const formSchema: FormSchema[] = [ component: 'Input', componentProps: { disabled: true, bordered: false, placeholder: '保存后按创建人显示' }, colProps: colHalf, - itemProps: { class: 'ps-workflow-item' }, }, { label: '担当', @@ -225,7 +224,6 @@ export const formSchema: FormSchema[] = [ component: 'Input', componentProps: { disabled: true, bordered: false }, colProps: colHalf, - itemProps: { class: 'ps-workflow-item' }, ifShow: ({ values }) => !!values.proofreadBy, }, { @@ -234,7 +232,6 @@ export const formSchema: FormSchema[] = [ component: 'Input', componentProps: { disabled: true, bordered: false }, colProps: colHalf, - itemProps: { class: 'ps-workflow-item' }, ifShow: ({ values }) => !!values.proofreadTime, }, { @@ -243,7 +240,6 @@ export const formSchema: FormSchema[] = [ component: 'Input', componentProps: { disabled: true, bordered: false }, colProps: colHalf, - itemProps: { class: 'ps-workflow-item' }, ifShow: ({ values }) => !!values.auditBy, }, { @@ -252,7 +248,6 @@ export const formSchema: FormSchema[] = [ component: 'Input', componentProps: { disabled: true, bordered: false }, colProps: colHalf, - itemProps: { class: 'ps-workflow-item' }, ifShow: ({ values }) => !!values.auditTime, }, { @@ -261,7 +256,6 @@ export const formSchema: FormSchema[] = [ component: 'Input', componentProps: { disabled: true, bordered: false }, colProps: colHalf, - itemProps: { class: 'ps-workflow-item' }, ifShow: ({ values }) => !!values.approveBy, }, { @@ -270,7 +264,6 @@ export const formSchema: FormSchema[] = [ component: 'Input', componentProps: { disabled: true, bordered: false }, colProps: colHalf, - itemProps: { class: 'ps-workflow-item' }, ifShow: ({ values }) => !!values.approveTime, }, ]; diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixerPsCompile/components/MesXslMixerPsCompileModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixerPsCompile/components/MesXslMixerPsCompileModal.vue index 4adf8ea..534409e 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslMixerPsCompile/components/MesXslMixerPsCompileModal.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixerPsCompile/components/MesXslMixerPsCompileModal.vue @@ -9,7 +9,7 @@ @ok="handleSubmit" >
- +
@@ -166,7 +166,13 @@ margin-bottom: 14px; } - :deep(.ps-workflow-item) { + :deep(#MesXslMixerPsCompileForm_compileBy), + :deep(#MesXslMixerPsCompileForm_proofreadBy), + :deep(#MesXslMixerPsCompileForm_proofreadTime), + :deep(#MesXslMixerPsCompileForm_auditBy), + :deep(#MesXslMixerPsCompileForm_auditTime), + :deep(#MesXslMixerPsCompileForm_approveBy), + :deep(#MesXslMixerPsCompileForm_approveTime) { margin-bottom: 8px; .ant-form-item-label > label { diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslMixerPsCompile/components/MesXslMixerPsCompileSelectModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslMixerPsCompile/components/MesXslMixerPsCompileSelectModal.vue new file mode 100644 index 0000000..3aecd1a --- /dev/null +++ b/jeecgboot-vue3/src/views/xslmes/mesXslMixerPsCompile/components/MesXslMixerPsCompileSelectModal.vue @@ -0,0 +1,101 @@ + + +