实现密炼物料种类配置关联解析功能,新增种类查找表加载与解析接口,优化选料弹窗层级与刷新功能,增强用户体验与系统稳定性。
This commit is contained in:
@@ -278,3 +278,31 @@ jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixe
|
||||
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A51】密炼物料种类配置菜单ID冲突修复 -----------
|
||||
jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_102__mes_xsl_mixer_material_kind_cfg.sql
|
||||
jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_103__mes_xsl_mixer_material_kind_cfg_menu_fix.sql
|
||||
|
||||
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】混炼示方种类改读密炼物料种类配置(生成/选料弹窗) -----------
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslMixerMaterialKindLookupVO.java
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerMaterialKindCfgService.java
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerMaterialKindCfgServiceImpl.java
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixerMaterialKindCfgController.java
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.api.ts
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||
|
||||
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】选料弹窗层级修复及关闭父弹窗时同步关闭 -----------
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||
|
||||
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】选料弹窗左侧物料小类树会话缓存 -----------
|
||||
jeecgboot-vue3/src/views/system/category/category.constants.ts
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||
|
||||
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】选料弹窗小类设置按钮 Popover 层级修复 -----------
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue
|
||||
|
||||
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】选料弹窗小类设置新增刷新分类字典 -----------
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||
|
||||
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】高层级弹窗内 Message 提示层级修复 -----------
|
||||
jeecgboot-vue3/src/design/public.less
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.modules.xslmes.entity.MesXslMixerMaterialKindCfg;
|
||||
import org.jeecg.modules.xslmes.service.IMesXslMixerMaterialKindCfgService;
|
||||
import org.jeecg.modules.xslmes.vo.MesXslMixerMaterialKindLookupVO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
@@ -72,6 +73,28 @@ public class MesXslMixerMaterialKindCfgController
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置展开与批量保存-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||
@Operation(summary = "MES密炼物料种类配置-加载种类查找表")
|
||||
@GetMapping(value = "/kindLookup")
|
||||
public Result<MesXslMixerMaterialKindLookupVO> kindLookup(
|
||||
@RequestParam(name = "tenantId", required = false) Integer tenantId) {
|
||||
return Result.OK(mesXslMixerMaterialKindCfgService.loadKindLookup(tenantId));
|
||||
}
|
||||
|
||||
@Operation(summary = "MES密炼物料种类配置-解析混炼示方明细种类")
|
||||
@GetMapping(value = "/resolveKind")
|
||||
public Result<String> resolveKind(
|
||||
@RequestParam(name = "minorCategoryId", required = false) String minorCategoryId,
|
||||
@RequestParam(name = "weighMode", required = false) String weighMode,
|
||||
@RequestParam(name = "minorCategoryName", required = false) String minorCategoryName,
|
||||
@RequestParam(name = "tenantId", required = false) Integer tenantId) {
|
||||
MesXslMixerMaterialKindLookupVO lookup = mesXslMixerMaterialKindCfgService.loadKindLookup(tenantId);
|
||||
String kind = mesXslMixerMaterialKindCfgService.resolveMixingMaterialKind(
|
||||
lookup, minorCategoryId, weighMode, minorCategoryName);
|
||||
return Result.OK(kind);
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||
|
||||
@AutoLog(value = "MES密炼物料种类配置-添加")
|
||||
@Operation(summary = "MES密炼物料种类配置-添加")
|
||||
@RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:add")
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.jeecg.modules.xslmes.service;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import java.util.List;
|
||||
import org.jeecg.modules.xslmes.entity.MesXslMixerMaterialKindCfg;
|
||||
import org.jeecg.modules.xslmes.vo.MesXslMixerMaterialKindLookupVO;
|
||||
|
||||
/**
|
||||
* MES 密炼物料种类配置
|
||||
@@ -23,4 +24,20 @@ public interface IMesXslMixerMaterialKindCfgService extends IService<MesXslMixer
|
||||
* 校验租户内种类键值/对应分类是否重复
|
||||
*/
|
||||
void checkDuplicate(MesXslMixerMaterialKindCfg line, String excludeId);
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||
/**
|
||||
* 加载种类配置查找表(按 category_ref_id / category_ref_code 关联)
|
||||
*/
|
||||
MesXslMixerMaterialKindLookupVO loadKindLookup(Integer tenantId);
|
||||
|
||||
/**
|
||||
* 解析混炼示方明细种类:称量方式优先,其次物料小类,最后小类名称兜底
|
||||
*/
|
||||
String resolveMixingMaterialKind(
|
||||
MesXslMixerMaterialKindLookupVO lookup,
|
||||
String minorCategoryId,
|
||||
String weighMode,
|
||||
String minorCategoryName);
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecMapper;
|
||||
import org.jeecg.modules.xslmes.service.IMesXslEquipmentLedgerService;
|
||||
import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecService;
|
||||
import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecSettingService;
|
||||
import org.jeecg.modules.xslmes.service.IMesXslMixerMaterialKindCfgService;
|
||||
import org.jeecg.modules.xslmes.service.IMesXslMixingSpecService;
|
||||
import org.jeecg.modules.xslmes.vo.MesXslMixerMaterialKindLookupVO;
|
||||
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateMachineVO;
|
||||
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGeneratePreviewItemVO;
|
||||
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGeneratePreviewVO;
|
||||
@@ -90,6 +92,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
@Resource
|
||||
private ISysCategoryService sysCategoryService;
|
||||
|
||||
@Resource
|
||||
private IMesXslMixerMaterialKindCfgService mesXslMixerMaterialKindCfgService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveMain(MesXslFormulaSpec main, List<MesXslFormulaSpecLine> lineList) {
|
||||
@@ -528,7 +533,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
}
|
||||
Map<String, MesMixerMaterial> mixerCache = new HashMap<>();
|
||||
Map<String, String> categoryNameCache = new HashMap<>();
|
||||
Map<String, Boolean> categoryRubberCache = new HashMap<>();
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】生成混炼示方种类改读密炼物料种类配置-----------
|
||||
MesXslMixerMaterialKindLookupVO kindLookup = mesXslMixerMaterialKindCfgService.loadKindLookup(null);
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】生成混炼示方种类改读密炼物料种类配置-----------
|
||||
Map<String, MesXslEquipmentLedger> equipmentCache = new HashMap<>();
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】F段终炼胶比重按配合示方整体PHR/体积汇总-----------
|
||||
BigDecimal compoundSpecificGravity = resolveCompoundSpecificGravity(formula, lines);
|
||||
@@ -555,7 +562,7 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
String materialStep = resolveMixingMaterialStep(row);
|
||||
int mixingColumn = resolveMixingColumn(row, formula);
|
||||
List<MesXslMixingSpecMaterial> materials = buildMixingMaterials(
|
||||
formula, lines, mixingColumn, materialStep, mixerCache, categoryNameCache, categoryRubberCache);
|
||||
formula, lines, mixingColumn, materialStep, mixerCache, categoryNameCache, kindLookup);
|
||||
for (MesXslFormulaMixingGenerateMachineVO machine : row.getMachines()) {
|
||||
if (machine == null || oConvertUtils.isEmpty(machine.getMachineId())) {
|
||||
continue;
|
||||
@@ -928,7 +935,7 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
String materialStep,
|
||||
Map<String, MesMixerMaterial> mixerCache,
|
||||
Map<String, String> categoryNameCache,
|
||||
Map<String, Boolean> categoryRubberCache) {
|
||||
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||
String stepFilter = StringUtils.isNotBlank(materialStep) ? materialStep.trim().toUpperCase() : "A";
|
||||
List<MesXslMixingSpecMaterial> materials = new ArrayList<>();
|
||||
int sort = 0;
|
||||
@@ -940,9 +947,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
if (lastBSegment > 0) {
|
||||
String motherSpecCode = appendFormulaCodeSuffix("B" + lastBSegment + rubberName, codeSuffix);
|
||||
BigDecimal motherWeight = resolveStageCumulativeTotal(formula, lines, lastBSegment);
|
||||
materials.add(createMotherRubberMaterial(motherSpecCode, rubberName, motherWeight, materials.size()));
|
||||
materials.add(createMotherRubberMaterial(motherSpecCode, rubberName, motherWeight, materials.size(), kindLookup));
|
||||
}
|
||||
appendQStageColumnAgents(lines, stageIndex, materials, mixerCache, categoryNameCache, categoryRubberCache);
|
||||
appendQStageColumnAgents(lines, stageIndex, materials, mixerCache, categoryNameCache, kindLookup);
|
||||
reindexMaterialSortNo(materials);
|
||||
return materials;
|
||||
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】F段加入最后一段B炼好胶料一条再加Q配合剂-----------
|
||||
@@ -951,7 +958,7 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
String rubberName = resolveRubberName(formula);
|
||||
String codeSuffix = resolveFormulaCodeSuffix(formula);
|
||||
if (bColumn <= 1) {
|
||||
appendBStageColumnAgents(lines, 1, materials, mixerCache, categoryNameCache, categoryRubberCache);
|
||||
appendBStageColumnAgents(lines, 1, materials, mixerCache, categoryNameCache, kindLookup);
|
||||
reindexMaterialSortNo(materials);
|
||||
return materials;
|
||||
}
|
||||
@@ -959,8 +966,8 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
int prevB = bColumn - 1;
|
||||
String motherSpecCode = appendFormulaCodeSuffix("B" + prevB + rubberName, codeSuffix);
|
||||
BigDecimal motherWeight = resolveStageCumulativeTotal(formula, lines, prevB);
|
||||
materials.add(createMotherRubberMaterial(motherSpecCode, rubberName, motherWeight, materials.size()));
|
||||
appendBStageColumnAgents(lines, bColumn, materials, mixerCache, categoryNameCache, categoryRubberCache);
|
||||
materials.add(createMotherRubberMaterial(motherSpecCode, rubberName, motherWeight, materials.size(), kindLookup));
|
||||
appendBStageColumnAgents(lines, bColumn, materials, mixerCache, categoryNameCache, kindLookup);
|
||||
reindexMaterialSortNo(materials);
|
||||
return materials;
|
||||
}
|
||||
@@ -981,7 +988,7 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
List<MesXslMixingSpecMaterial> materials,
|
||||
Map<String, MesMixerMaterial> mixerCache,
|
||||
Map<String, String> categoryNameCache,
|
||||
Map<String, Boolean> categoryRubberCache) {
|
||||
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||
for (MesXslFormulaSpecLine line : lines) {
|
||||
if (!isLineStep(line, "Q")) {
|
||||
continue;
|
||||
@@ -991,7 +998,7 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
continue;
|
||||
}
|
||||
materials.add(
|
||||
toMixingMaterial(line, unitWeight, materials.size(), mixerCache, categoryNameCache, categoryRubberCache));
|
||||
toMixingMaterial(line, unitWeight, materials.size(), mixerCache, categoryNameCache, kindLookup));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1002,7 +1009,7 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
List<MesXslMixingSpecMaterial> materials,
|
||||
Map<String, MesMixerMaterial> mixerCache,
|
||||
Map<String, String> categoryNameCache,
|
||||
Map<String, Boolean> categoryRubberCache) {
|
||||
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||
for (MesXslFormulaSpecLine line : lines) {
|
||||
if (!isLineStep(line, "A")) {
|
||||
continue;
|
||||
@@ -1012,18 +1019,26 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
continue;
|
||||
}
|
||||
materials.add(
|
||||
toMixingMaterial(line, unitWeight, materials.size(), mixerCache, categoryNameCache, categoryRubberCache));
|
||||
toMixingMaterial(line, unitWeight, materials.size(), mixerCache, categoryNameCache, kindLookup));
|
||||
}
|
||||
}
|
||||
|
||||
/** 上一段密炼产出胶料(一条):示方编号 B{n-1}+胶料名,种类=胶料 */
|
||||
/** 上一段密炼产出胶料(一条):示方编号 B{n-1}+胶料名,种类读配置表 */
|
||||
private MesXslMixingSpecMaterial createMotherRubberMaterial(
|
||||
String motherSpecCode, String rubberName, BigDecimal unitWeight, int sortNo) {
|
||||
String motherSpecCode,
|
||||
String rubberName,
|
||||
BigDecimal unitWeight,
|
||||
int sortNo,
|
||||
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||
MesXslMixingSpecMaterial material = new MesXslMixingSpecMaterial();
|
||||
material.setSortNo(sortNo);
|
||||
material.setMixerMaterialName(motherSpecCode);
|
||||
material.setMixerMaterialDesc(StringUtils.isNotBlank(rubberName) ? rubberName : motherSpecCode);
|
||||
material.setMaterialKind("胶料");
|
||||
String rubberKind =
|
||||
kindLookup != null && StringUtils.isNotBlank(kindLookup.getRubberKindName())
|
||||
? kindLookup.getRubberKindName()
|
||||
: "胶料";
|
||||
material.setMaterialKind(rubberKind);
|
||||
material.setUnitWeight(unitWeight);
|
||||
return material;
|
||||
}
|
||||
@@ -1103,14 +1118,14 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
int sortNo,
|
||||
Map<String, MesMixerMaterial> mixerCache,
|
||||
Map<String, String> categoryNameCache,
|
||||
Map<String, Boolean> categoryRubberCache) {
|
||||
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||
MesXslMixingSpecMaterial material = new MesXslMixingSpecMaterial();
|
||||
material.setSortNo(sortNo);
|
||||
material.setMixerMaterialName(line.getMixerMaterialName());
|
||||
material.setMixerMaterialDesc(
|
||||
StringUtils.isNotBlank(line.getMaterialDesc()) ? line.getMaterialDesc() : line.getMixerMaterialName());
|
||||
material.setUnitWeight(unitWeight);
|
||||
fillMaterialCategory(material, line.getMixerMaterialId(), line, mixerCache, categoryNameCache, categoryRubberCache);
|
||||
fillMaterialCategory(material, line.getMixerMaterialId(), line, mixerCache, categoryNameCache, kindLookup);
|
||||
return material;
|
||||
}
|
||||
|
||||
@@ -1136,7 +1151,7 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
MesXslFormulaSpecLine line,
|
||||
Map<String, MesMixerMaterial> mixerCache,
|
||||
Map<String, String> categoryNameCache,
|
||||
Map<String, Boolean> categoryRubberCache) {
|
||||
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||
if (oConvertUtils.isEmpty(mixerMaterialId)) {
|
||||
return;
|
||||
}
|
||||
@@ -1149,58 +1164,11 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
String minorName = resolveCategoryName(mixer.getMinorCategoryId(), categoryNameCache);
|
||||
material.setMaterialMajor(majorName);
|
||||
material.setMaterialMinor(minorName);
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】生成混炼示方时称量方式优先映射种类-----------
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】生成混炼示方种类改读密炼物料种类配置-----------
|
||||
material.setMaterialKind(
|
||||
resolveMixingMaterialKind(weighMode, mixer.getMinorCategoryId(), minorName, categoryRubberCache));
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】生成混炼示方时称量方式优先映射种类-----------
|
||||
}
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】生成混炼示方时称量方式优先映射种类-----------
|
||||
/**
|
||||
* 种类:配合示方称量方式优先;否则物料小类勾选「胶料」则显示「胶料」,否则显示小类名称。
|
||||
*/
|
||||
private String resolveMixingMaterialKind(
|
||||
String weighMode, String minorCategoryId, String minorCategoryName, Map<String, Boolean> categoryRubberCache) {
|
||||
String weighKind = resolveWeighModeMaterialKind(weighMode);
|
||||
if (StringUtils.isNotBlank(weighKind)) {
|
||||
return weighKind;
|
||||
}
|
||||
if (isCategoryRubber(minorCategoryId, categoryRubberCache)) {
|
||||
return "胶料";
|
||||
}
|
||||
if (StringUtils.isNotBlank(minorCategoryName)) {
|
||||
return minorCategoryName;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 配合示方自动/人工称量 -> 混炼示方种类 */
|
||||
private String resolveWeighModeMaterialKind(String weighMode) {
|
||||
if (StringUtils.isBlank(weighMode)) {
|
||||
return null;
|
||||
}
|
||||
String normalized = weighMode.trim();
|
||||
String lower = normalized.toLowerCase();
|
||||
if (lower.startsWith("auto") || normalized.contains("自动")) {
|
||||
return "自动";
|
||||
}
|
||||
if ("manual".equals(lower) || normalized.contains("人工")) {
|
||||
return "人工";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】生成混炼示方时称量方式优先映射种类-----------
|
||||
|
||||
private boolean isCategoryRubber(String categoryId, Map<String, Boolean> cache) {
|
||||
if (oConvertUtils.isEmpty(categoryId)) {
|
||||
return false;
|
||||
}
|
||||
return Boolean.TRUE.equals(cache.computeIfAbsent(categoryId, this::loadCategoryIsRubber));
|
||||
}
|
||||
|
||||
private Boolean loadCategoryIsRubber(String categoryId) {
|
||||
SysCategory category = sysCategoryService.getById(categoryId);
|
||||
return category != null && "1".equals(category.getIsRubber());
|
||||
mesXslMixerMaterialKindCfgService.resolveMixingMaterialKind(
|
||||
kindLookup, mixer.getMinorCategoryId(), weighMode, minorName));
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】生成混炼示方种类改读密炼物料种类配置-----------
|
||||
}
|
||||
|
||||
private String resolveCategoryName(String categoryId, Map<String, String> cache) {
|
||||
|
||||
@@ -7,7 +7,9 @@ import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
@@ -25,6 +27,8 @@ import org.jeecg.modules.system.service.ISysDictService;
|
||||
import org.jeecg.modules.xslmes.entity.MesXslMixerMaterialKindCfg;
|
||||
import org.jeecg.modules.xslmes.mapper.MesXslMixerMaterialKindCfgMapper;
|
||||
import org.jeecg.modules.xslmes.service.IMesXslMixerMaterialKindCfgService;
|
||||
import org.jeecg.modules.xslmes.vo.MesXslMixerMaterialKindLookupVO;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -295,4 +299,109 @@ public class MesXslMixerMaterialKindCfgServiceImpl
|
||||
}
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置展开与批量保存-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||
private static final String DEFAULT_RUBBER_KIND_NAME = "胶料";
|
||||
|
||||
@Override
|
||||
public MesXslMixerMaterialKindLookupVO loadKindLookup(Integer tenantId) {
|
||||
LambdaQueryWrapper<MesXslMixerMaterialKindCfg> qw = new LambdaQueryWrapper<>();
|
||||
qw.and(q -> q.eq(MesXslMixerMaterialKindCfg::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesXslMixerMaterialKindCfg::getDelFlag));
|
||||
Integer resolvedTenantId = resolveTenantId(tenantId);
|
||||
if (resolvedTenantId != null && MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
||||
qw.eq(MesXslMixerMaterialKindCfg::getTenantId, resolvedTenantId);
|
||||
}
|
||||
qw.orderByAsc(MesXslMixerMaterialKindCfg::getPriority).orderByAsc(MesXslMixerMaterialKindCfg::getKindKey);
|
||||
List<MesXslMixerMaterialKindCfg> rows = list(qw);
|
||||
|
||||
MesXslMixerMaterialKindLookupVO lookup = new MesXslMixerMaterialKindLookupVO();
|
||||
Map<String, String> byRefId = new LinkedHashMap<>();
|
||||
Map<String, String> byRefCode = new LinkedHashMap<>();
|
||||
String rubberKindName = null;
|
||||
if (rows != null) {
|
||||
for (MesXslMixerMaterialKindCfg row : rows) {
|
||||
if (row == null || oConvertUtils.isEmpty(row.getKindName())) {
|
||||
continue;
|
||||
}
|
||||
String kindName = row.getKindName().trim();
|
||||
if (oConvertUtils.isNotEmpty(row.getCategoryRefId()) && !byRefId.containsKey(row.getCategoryRefId().trim())) {
|
||||
byRefId.put(row.getCategoryRefId().trim(), kindName);
|
||||
}
|
||||
if (oConvertUtils.isNotEmpty(row.getCategoryRefCode())) {
|
||||
String refCode = row.getCategoryRefCode().trim();
|
||||
if (!byRefCode.containsKey(refCode)) {
|
||||
byRefCode.put(refCode, kindName);
|
||||
}
|
||||
String lowerCode = refCode.toLowerCase();
|
||||
if (!lowerCode.equals(refCode) && !byRefCode.containsKey(lowerCode)) {
|
||||
byRefCode.put(lowerCode, kindName);
|
||||
}
|
||||
}
|
||||
if (rubberKindName == null && DEFAULT_RUBBER_KIND_NAME.equals(kindName)) {
|
||||
rubberKindName = kindName;
|
||||
}
|
||||
}
|
||||
}
|
||||
lookup.setByRefId(byRefId);
|
||||
lookup.setByRefCode(byRefCode);
|
||||
lookup.setRubberKindName(oConvertUtils.isNotEmpty(rubberKindName) ? rubberKindName : DEFAULT_RUBBER_KIND_NAME);
|
||||
return lookup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveMixingMaterialKind(
|
||||
MesXslMixerMaterialKindLookupVO lookup,
|
||||
String minorCategoryId,
|
||||
String weighMode,
|
||||
String minorCategoryName) {
|
||||
if (lookup == null) {
|
||||
lookup = loadKindLookup(null);
|
||||
}
|
||||
if (oConvertUtils.isNotEmpty(weighMode)) {
|
||||
String fromWeighMode = matchKindFromLookup(lookup, weighMode.trim());
|
||||
if (oConvertUtils.isNotEmpty(fromWeighMode)) {
|
||||
return fromWeighMode;
|
||||
}
|
||||
}
|
||||
if (oConvertUtils.isNotEmpty(minorCategoryId)) {
|
||||
String fromMinor = matchKindFromLookup(lookup, minorCategoryId.trim());
|
||||
if (oConvertUtils.isNotEmpty(fromMinor)) {
|
||||
return fromMinor;
|
||||
}
|
||||
}
|
||||
if (oConvertUtils.isNotEmpty(minorCategoryName)) {
|
||||
return minorCategoryName.trim();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String matchKindFromLookup(MesXslMixerMaterialKindLookupVO lookup, String key) {
|
||||
if (lookup == null || oConvertUtils.isEmpty(key)) {
|
||||
return null;
|
||||
}
|
||||
Map<String, String> byRefId = lookup.getByRefId();
|
||||
if (byRefId != null && byRefId.containsKey(key)) {
|
||||
return byRefId.get(key);
|
||||
}
|
||||
Map<String, String> byRefCode = lookup.getByRefCode();
|
||||
if (byRefCode == null || byRefCode.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (byRefCode.containsKey(key)) {
|
||||
return byRefCode.get(key);
|
||||
}
|
||||
String lower = key.toLowerCase();
|
||||
if (byRefCode.containsKey(lower)) {
|
||||
return byRefCode.get(lower);
|
||||
}
|
||||
if (StringUtils.isNotBlank(key)) {
|
||||
for (Map.Entry<String, String> entry : byRefCode.entrySet()) {
|
||||
if (entry.getKey() != null && key.contains(entry.getKey())) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.jeecg.modules.xslmes.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 密炼物料种类配置查找表(按对应分类/字典项关联)
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "密炼物料种类配置查找表")
|
||||
public class MesXslMixerMaterialKindLookupVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "对应分类/字典项ID -> 种类名称")
|
||||
private Map<String, String> byRefId = new LinkedHashMap<>();
|
||||
|
||||
@Schema(description = "对应分类/字典项编码 -> 种类名称")
|
||||
private Map<String, String> byRefCode = new LinkedHashMap<>();
|
||||
|
||||
@Schema(description = "胶料种类名称(母炼胶行兜底)")
|
||||
private String rubberKindName;
|
||||
}
|
||||
@@ -56,6 +56,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 高层级业务弹窗(如混炼示方选料 z-index 1500)打开时,顶部提示需置于弹窗之上
|
||||
.ant-message,
|
||||
.ant-notification {
|
||||
z-index: 2200 !important;
|
||||
}
|
||||
|
||||
// =======================================
|
||||
// ============ [sjl] 按钮组样式 ==========
|
||||
// =======================================
|
||||
|
||||
@@ -130,7 +130,39 @@ function normalizeTreeSelectNodes(nodes: unknown): Recordable[] {
|
||||
}
|
||||
|
||||
/** 加载 MES 物料分类树:根下物料大类 + 各物料小类(供密炼物料/混炼示方选料复用) */
|
||||
export async function loadMesMaterialCategoryTreeData(): Promise<MesMaterialCategoryTreeLoadResult> {
|
||||
let mesMaterialCategoryTreeCache: MesMaterialCategoryTreeLoadResult | null = null;
|
||||
let mesMaterialCategoryTreeLoading: Promise<MesMaterialCategoryTreeLoadResult> | null = null;
|
||||
|
||||
export function hasMesMaterialCategoryTreeCache() {
|
||||
return !!(mesMaterialCategoryTreeCache?.minors?.length || mesMaterialCategoryTreeCache?.majors?.length);
|
||||
}
|
||||
|
||||
export function clearMesMaterialCategoryTreeCache() {
|
||||
mesMaterialCategoryTreeCache = null;
|
||||
mesMaterialCategoryTreeLoading = null;
|
||||
}
|
||||
|
||||
export async function loadMesMaterialCategoryTreeData(forceReload = false): Promise<MesMaterialCategoryTreeLoadResult> {
|
||||
if (!forceReload && mesMaterialCategoryTreeCache) {
|
||||
return mesMaterialCategoryTreeCache;
|
||||
}
|
||||
if (!forceReload && mesMaterialCategoryTreeLoading) {
|
||||
return mesMaterialCategoryTreeLoading;
|
||||
}
|
||||
mesMaterialCategoryTreeLoading = fetchMesMaterialCategoryTreeData()
|
||||
.then((result) => {
|
||||
if (result.minors.length || result.majors.length) {
|
||||
mesMaterialCategoryTreeCache = result;
|
||||
}
|
||||
return result;
|
||||
})
|
||||
.finally(() => {
|
||||
mesMaterialCategoryTreeLoading = null;
|
||||
});
|
||||
return mesMaterialCategoryTreeLoading;
|
||||
}
|
||||
|
||||
async function fetchMesMaterialCategoryTreeData(): Promise<MesMaterialCategoryTreeLoadResult> {
|
||||
// 优先 loadTreeRoot(与密炼物料列表页一致,已验证可用)
|
||||
try {
|
||||
const treeRes = await loadTreeData({ async: false, pcode: MATERIAL_ROOT_CODE });
|
||||
|
||||
@@ -11,12 +11,18 @@ enum Api {
|
||||
importExcel = '/xslmes/mesXslMixerMaterialKindCfg/importExcel',
|
||||
exportXls = '/xslmes/mesXslMixerMaterialKindCfg/exportXls',
|
||||
queryById = '/xslmes/mesXslMixerMaterialKindCfg/queryById',
|
||||
kindLookup = '/xslmes/mesXslMixerMaterialKindCfg/kindLookup',
|
||||
resolveKind = '/xslmes/mesXslMixerMaterialKindCfg/resolveKind',
|
||||
}
|
||||
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
export const queryById = (params) => defHttp.get({ url: Api.queryById, params });
|
||||
|
||||
export const loadKindLookup = (params?) => defHttp.get({ url: Api.kindLookup, params });
|
||||
|
||||
export const resolveKind = (params) => defHttp.get({ url: Api.resolveKind, params });
|
||||
|
||||
export const expandLines = (params) => defHttp.get({ url: Api.expandLines, params });
|
||||
|
||||
export const addBatch = (params) => defHttp.post({ url: Api.addBatch, params }, { successMessageMode: 'none' });
|
||||
|
||||
@@ -967,52 +967,135 @@ export function sanitizeMixingMaterialPickerHiddenCategoryIds(allMinorIds: strin
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗小类树为空时重置隐藏配置-----------
|
||||
|
||||
/** 解析混炼示方明细种类:小类勾选胶料则显示「胶料」,否则显示小类名 */
|
||||
export function resolveMixingMaterialKindFromCategory(isRubber?: unknown, minorName?: string) {
|
||||
if (isRubber === '1' || isRubber === 1 || isRubber === true) {
|
||||
return '胶料';
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】混炼示方种类改读密炼物料种类配置-----------
|
||||
export interface MixerMaterialKindLookup {
|
||||
byRefId: Record<string, string>;
|
||||
byRefCode: Record<string, string>;
|
||||
rubberKindName?: string;
|
||||
}
|
||||
|
||||
export const EMPTY_MIXER_MATERIAL_KIND_LOOKUP: MixerMaterialKindLookup = {
|
||||
byRefId: {},
|
||||
byRefCode: {},
|
||||
rubberKindName: '胶料',
|
||||
};
|
||||
|
||||
let mixingMaterialKindLookupCache: MixerMaterialKindLookup | null = null;
|
||||
let mixingMaterialKindLookupPromise: Promise<MixerMaterialKindLookup> | null = null;
|
||||
|
||||
/** 加载密炼物料种类配置查找表(带内存缓存) */
|
||||
export async function loadMixingMaterialKindLookup(forceReload = false): Promise<MixerMaterialKindLookup> {
|
||||
if (!forceReload && mixingMaterialKindLookupCache) {
|
||||
return mixingMaterialKindLookupCache;
|
||||
}
|
||||
if (!forceReload && mixingMaterialKindLookupPromise) {
|
||||
return mixingMaterialKindLookupPromise;
|
||||
}
|
||||
mixingMaterialKindLookupPromise = (async () => {
|
||||
try {
|
||||
const { loadKindLookup } = await import('../mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.api');
|
||||
const raw = await loadKindLookup();
|
||||
const lookup: MixerMaterialKindLookup = {
|
||||
byRefId: raw?.byRefId || {},
|
||||
byRefCode: raw?.byRefCode || {},
|
||||
rubberKindName: raw?.rubberKindName || '胶料',
|
||||
};
|
||||
mixingMaterialKindLookupCache = lookup;
|
||||
return lookup;
|
||||
} catch {
|
||||
return EMPTY_MIXER_MATERIAL_KIND_LOOKUP;
|
||||
} finally {
|
||||
mixingMaterialKindLookupPromise = null;
|
||||
}
|
||||
})();
|
||||
return mixingMaterialKindLookupPromise;
|
||||
}
|
||||
|
||||
/** 清除种类配置缓存(配置变更后可调用) */
|
||||
export function clearMixingMaterialKindLookupCache() {
|
||||
mixingMaterialKindLookupCache = null;
|
||||
mixingMaterialKindLookupPromise = null;
|
||||
}
|
||||
|
||||
function matchKindFromLookup(lookup: MixerMaterialKindLookup | null | undefined, key?: string) {
|
||||
if (!lookup || key == null || String(key).trim() === '') {
|
||||
return '';
|
||||
}
|
||||
const normalized = String(key).trim();
|
||||
if (lookup.byRefId?.[normalized]) {
|
||||
return lookup.byRefId[normalized];
|
||||
}
|
||||
if (lookup.byRefCode?.[normalized]) {
|
||||
return lookup.byRefCode[normalized];
|
||||
}
|
||||
const lower = normalized.toLowerCase();
|
||||
if (lookup.byRefCode?.[lower]) {
|
||||
return lookup.byRefCode[lower];
|
||||
}
|
||||
for (const [code, kindName] of Object.entries(lookup.byRefCode || {})) {
|
||||
if (code && normalized.includes(code)) {
|
||||
return kindName;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/** 解析混炼示方明细种类:称量方式优先,其次物料小类 ID,最后小类名称兜底 */
|
||||
export function resolveMixingMaterialKindFromLookup(
|
||||
lookup: MixerMaterialKindLookup | null | undefined,
|
||||
weighMode?: string,
|
||||
minorCategoryId?: string,
|
||||
minorCategoryName?: string,
|
||||
) {
|
||||
const fromWeighMode = matchKindFromLookup(lookup, weighMode);
|
||||
if (fromWeighMode) {
|
||||
return fromWeighMode;
|
||||
}
|
||||
const fromMinorId = matchKindFromLookup(lookup, minorCategoryId);
|
||||
if (fromMinorId) {
|
||||
return fromMinorId;
|
||||
}
|
||||
if (minorCategoryName != null && String(minorCategoryName).trim() !== '') {
|
||||
return String(minorCategoryName).trim();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/** @deprecated 保留兼容,请改用 resolveMixingMaterialKindFromLookup */
|
||||
export function resolveMixingMaterialKindFromCategory(_isRubber?: unknown, minorName?: string) {
|
||||
return minorName != null && String(minorName).trim() !== '' ? String(minorName).trim() : '';
|
||||
}
|
||||
|
||||
/** @deprecated 保留兼容,请改用 resolveMixingMaterialKindFromLookup */
|
||||
export function resolveMixingMaterialKindFromWeighMode(_weighMode?: string) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/** 选料确认时种类:读密炼物料种类配置表 */
|
||||
export function resolveMixingMaterialKindForPicker(
|
||||
lookup: MixerMaterialKindLookup | null | undefined,
|
||||
weighMode: string | undefined,
|
||||
minorCategoryId?: string,
|
||||
minorCategoryName?: string,
|
||||
) {
|
||||
return resolveMixingMaterialKindFromLookup(lookup, weighMode, minorCategoryId, minorCategoryName);
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】混炼示方种类改读密炼物料种类配置-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗自动/人工称量列与种类映射-----------
|
||||
/** 与配合示方「自动/人工」列相同字典 */
|
||||
export const MIXING_MATERIAL_PICKER_WEIGH_MODE_DICT = 'xslmes_formula_spec_weigh_mode';
|
||||
|
||||
/** 选料弹窗表格列(隐藏 ERP 编号,新增仅本次有效的自动/人工称量) */
|
||||
/** 选料弹窗表格列(隐藏 ERP 编号,新增种类列与自动/人工称量) */
|
||||
export const mixingMaterialPickerTableColumns: BasicColumn[] = [
|
||||
{ title: '物料编码', align: 'center', width: 120, dataIndex: 'materialCode' },
|
||||
{ title: '物料名称', align: 'center', width: 160, dataIndex: 'materialName' },
|
||||
{ title: '自动/人工称量', align: 'center', width: 132, dataIndex: 'pickerWeighMode' },
|
||||
{ title: '种类', align: 'center', width: 100, dataIndex: 'pickerMaterialKind' },
|
||||
{ title: '物料大类', align: 'center', width: 120, dataIndex: 'majorCategoryId_dictText' },
|
||||
{ title: '物料小类', align: 'center', width: 120, dataIndex: 'minorCategoryId_dictText' },
|
||||
{ title: '物料描述', align: 'center', width: 180, ellipsis: true, dataIndex: 'materialDesc' },
|
||||
];
|
||||
|
||||
/** 配合示方称量方式 -> 混炼示方种类(与后端 resolveWeighModeMaterialKind 一致) */
|
||||
export function resolveMixingMaterialKindFromWeighMode(weighMode?: string) {
|
||||
if (weighMode == null || String(weighMode).trim() === '') {
|
||||
return '';
|
||||
}
|
||||
const normalized = String(weighMode).trim();
|
||||
const lower = normalized.toLowerCase();
|
||||
if (lower.startsWith('auto') || normalized.includes('自动')) {
|
||||
return '自动';
|
||||
}
|
||||
if (lower === 'manual' || normalized.includes('人工')) {
|
||||
return '人工';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/** 选料确认时种类:称量方式优先,否则按小类胶料/小类名 */
|
||||
export function resolveMixingMaterialKindForPicker(weighMode: string | undefined, isRubber?: unknown, minorName?: string) {
|
||||
const fromWeighMode = resolveMixingMaterialKindFromWeighMode(weighMode);
|
||||
if (fromWeighMode) {
|
||||
return fromWeighMode;
|
||||
}
|
||||
return resolveMixingMaterialKindFromCategory(isRubber, minorName);
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗自动/人工称量列与种类映射-----------
|
||||
|
||||
/** 选择密炼物料后回填混炼示方橡胶及配合剂明细行 */
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
v-model:open="popoverOpen"
|
||||
trigger="click"
|
||||
placement="bottomRight"
|
||||
:getPopupContainer="getPopoverContainer"
|
||||
:overlayClassName="`${prefixCls}__popover`"
|
||||
@open-change="handleOpenChange"
|
||||
>
|
||||
@@ -14,7 +15,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<Spin :spinning="loading">
|
||||
<Spin :spinning="loading || refreshing">
|
||||
<div v-if="!loading && !groupedCategories.length" :class="`${prefixCls}__empty`">
|
||||
暂无物料小类,请确认分类字典 XSLMES_MATERIAL 已配置
|
||||
</div>
|
||||
@@ -35,15 +36,16 @@
|
||||
</div>
|
||||
</Spin>
|
||||
<div :class="`${prefixCls}__footer`">
|
||||
<a-button size="small" :disabled="loading || !allCategoryIds.length" @click="handleReset">重置</a-button>
|
||||
<a-button size="small" type="primary" :disabled="loading || !allCategoryIds.length" @click="handleSave">保存</a-button>
|
||||
<a-button size="small" :loading="refreshing" :disabled="loading" @click="handleRefresh">刷新</a-button>
|
||||
<div :class="`${prefixCls}__footer-actions`">
|
||||
<a-button size="small" :disabled="loading || refreshing || !allCategoryIds.length" @click="handleReset">重置</a-button>
|
||||
<a-button size="small" type="primary" :disabled="loading || refreshing || !allCategoryIds.length" @click="handleSave">保存</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<a-tooltip title="小类展示设置">
|
||||
<a-button size="small" class="mixing-material-category-setting-btn" :disabled="loading" @click.stop>
|
||||
<Icon icon="ant-design:setting-outlined" />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-button size="small" class="mixing-material-category-setting-btn" :disabled="loading" title="小类展示设置">
|
||||
<Icon icon="ant-design:setting-outlined" />
|
||||
</a-button>
|
||||
</Popover>
|
||||
</template>
|
||||
|
||||
@@ -71,13 +73,21 @@
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
refreshing: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:hiddenCategoryIds', 'change']);
|
||||
const emit = defineEmits(['update:hiddenCategoryIds', 'change', 'refresh']);
|
||||
|
||||
const popoverOpen = ref(false);
|
||||
const draftVisibleIds = ref<string[]>([]);
|
||||
|
||||
function getPopoverContainer() {
|
||||
return document.body;
|
||||
}
|
||||
|
||||
const allCategoryIds = computed(() => (props.categories || []).map((item) => item.id));
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗小类设置按大类分组展示-----------
|
||||
@@ -156,6 +166,12 @@
|
||||
draftVisibleIds.value = [...allCategoryIds.value];
|
||||
}
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】小类设置刷新分类字典-----------
|
||||
function handleRefresh() {
|
||||
emit('refresh');
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】小类设置刷新分类字典-----------
|
||||
|
||||
function handleSave() {
|
||||
const visibleSet = new Set(draftVisibleIds.value.map(String));
|
||||
const hidden = allCategoryIds.value.filter((id) => !visibleSet.has(String(id)));
|
||||
@@ -175,6 +191,8 @@
|
||||
|
||||
<style lang="less">
|
||||
.mixing-material-category-setting__popover {
|
||||
z-index: 1600 !important;
|
||||
|
||||
.ant-popover-inner-content {
|
||||
width: 320px;
|
||||
max-width: 80vw;
|
||||
@@ -213,9 +231,16 @@
|
||||
|
||||
.mixing-material-category-setting__footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid var(--border-color-base, #f0f0f0);
|
||||
}
|
||||
|
||||
.mixing-material-category-setting__footer-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
title="选择密炼物料"
|
||||
:width="1180"
|
||||
:getContainer="getModalContainer"
|
||||
:width="1280"
|
||||
:zIndex="1500"
|
||||
wrapClassName="mixing-material-picker-modal-wrap"
|
||||
@register="registerModal"
|
||||
@ok="handleOk"
|
||||
>
|
||||
@@ -21,7 +22,9 @@
|
||||
v-model:hiddenCategoryIds="hiddenCategoryIds"
|
||||
:categories="allMinorCategories"
|
||||
:loading="treeLoading"
|
||||
:refreshing="categoryRefreshing"
|
||||
@change="handleCategoryVisibilityChange"
|
||||
@refresh="handleRefreshCategoryTree"
|
||||
/>
|
||||
</div>
|
||||
<div class="mixing-material-picker-body">
|
||||
@@ -55,6 +58,9 @@
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'pickerMaterialKind'">
|
||||
{{ resolvePickerMaterialKind(record) }}
|
||||
</template>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
@@ -64,19 +70,20 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { Spin } from 'ant-design-vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicTable, useTable } from '/@/components/Table';
|
||||
import { BasicTree } from '/@/components/Tree';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { loadMesMaterialCategoryTreeData } from '/@/views/system/category/category.constants';
|
||||
import { loadMesMaterialCategoryTreeData, hasMesMaterialCategoryTreeCache } from '/@/views/system/category/category.constants';
|
||||
import { list as mixerList, queryById as queryMixerById } from '/@/views/mes/material/MesMixerMaterial.api';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
|
||||
import MesXslMixingMaterialCategorySetting from './MesXslMixingMaterialCategorySetting.vue';
|
||||
import {
|
||||
applyMixingMaterialFromSelection,
|
||||
EMPTY_MIXER_MATERIAL_KIND_LOOKUP,
|
||||
loadMixingMaterialKindLookup,
|
||||
loadMixingMaterialPickerHiddenCategoryIds,
|
||||
MIXING_MATERIAL_PICKER_WEIGH_MODE_DICT,
|
||||
mixingMaterialPickerTableColumns,
|
||||
@@ -84,6 +91,7 @@
|
||||
sanitizeMixingMaterialPickerHiddenCategoryIds,
|
||||
saveMixingMaterialPickerHiddenCategoryIds,
|
||||
type MixingMaterialPickerCategoryItem,
|
||||
type MixerMaterialKindLookup,
|
||||
} from '../MesXslMixingSpec.data';
|
||||
import type { KeyType } from '/@/components/Tree/src/types/tree';
|
||||
|
||||
@@ -100,15 +108,13 @@
|
||||
const selectedCategoryKeys = ref<KeyType[]>([TREE_ALL]);
|
||||
const expandedCategoryKeys = ref<KeyType[]>([TREE_ALL]);
|
||||
const selectedRow = ref<Recordable | null>(null);
|
||||
const categoryRubberMap = ref<Record<string, boolean>>({});
|
||||
const kindLookup = ref<MixerMaterialKindLookup>(EMPTY_MIXER_MATERIAL_KIND_LOOKUP);
|
||||
const pickerWeighModeMap = ref<Record<string, string>>({});
|
||||
const pickerInitializing = ref(false);
|
||||
const categoryRefreshing = ref(false);
|
||||
|
||||
const hiddenCategoryIdSet = computed(() => new Set(hiddenCategoryIds.value.map(String)));
|
||||
|
||||
function getModalContainer() {
|
||||
return document.body;
|
||||
}
|
||||
|
||||
function getSelectPopupContainer() {
|
||||
return document.body;
|
||||
}
|
||||
@@ -179,7 +185,7 @@
|
||||
pagination: { pageSize: 10 },
|
||||
canResize: false,
|
||||
showIndexColumn: true,
|
||||
immediate: true,
|
||||
immediate: false,
|
||||
beforeFetch: (params) => {
|
||||
const next = { ...params, ...selectedCategoryFilter.value };
|
||||
const kw = keyword.value?.trim();
|
||||
@@ -200,10 +206,12 @@
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗打开时初始化(对齐其他SelectModal)-----------
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async () => {
|
||||
setModalProps({ zIndex: 1500 });
|
||||
await initPickerModal();
|
||||
});
|
||||
|
||||
async function initPickerModal() {
|
||||
pickerInitializing.value = true;
|
||||
selectedRow.value = null;
|
||||
keyword.value = '';
|
||||
pickerWeighModeMap.value = {};
|
||||
@@ -211,38 +219,26 @@
|
||||
hiddenCategoryIds.value = loadMixingMaterialPickerHiddenCategoryIds();
|
||||
selectedCategoryKeys.value = [TREE_ALL];
|
||||
setModalProps({ confirmLoading: false });
|
||||
await loadMaterialCategoryTree();
|
||||
reloadTable();
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】选料弹窗先加载左侧树再查右侧列表-----------
|
||||
try {
|
||||
await loadMaterialCategoryTree();
|
||||
kindLookup.value = await loadMixingMaterialKindLookup(false);
|
||||
reloadTable();
|
||||
} finally {
|
||||
pickerInitializing.value = false;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】选料弹窗先加载左侧树再查右侧列表-----------
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadMaterialCategoryTree();
|
||||
});
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗打开时初始化(对齐其他SelectModal)-----------
|
||||
|
||||
async function loadMaterialCategoryTree() {
|
||||
treeLoading.value = true;
|
||||
async function loadMaterialCategoryTree(forceReload = false) {
|
||||
const hasCachedTree = !forceReload && (hasMesMaterialCategoryTreeCache() || rawCategoryTree.value.length > 0);
|
||||
if (forceReload || !hasCachedTree) {
|
||||
treeLoading.value = true;
|
||||
}
|
||||
try {
|
||||
const { majors, minors, treeNodes } = await loadMesMaterialCategoryTreeData();
|
||||
rawCategoryTree.value = treeNodes;
|
||||
allMajorCategories.value = majors;
|
||||
allMinorCategories.value = minors;
|
||||
|
||||
const sanitizedHidden = sanitizeMixingMaterialPickerHiddenCategoryIds(
|
||||
minors.map((item) => item.id),
|
||||
hiddenCategoryIds.value,
|
||||
);
|
||||
if (sanitizedHidden.length !== hiddenCategoryIds.value.length) {
|
||||
hiddenCategoryIds.value = sanitizedHidden;
|
||||
saveMixingMaterialPickerHiddenCategoryIds(sanitizedHidden);
|
||||
}
|
||||
|
||||
categoryRubberMap.value = {};
|
||||
syncExpandedCategoryKeys();
|
||||
|
||||
if (!minors.length) {
|
||||
createMessage.warning('未加载到物料小类,请确认分类字典根编码 XSLMES_MATERIAL 及其下级分类已配置。');
|
||||
}
|
||||
const { majors, minors, treeNodes } = await loadMesMaterialCategoryTreeData(forceReload);
|
||||
applyMaterialCategoryTreeData(majors, minors, treeNodes);
|
||||
} catch {
|
||||
rawCategoryTree.value = [];
|
||||
allMajorCategories.value = [];
|
||||
@@ -253,6 +249,60 @@
|
||||
}
|
||||
}
|
||||
|
||||
function applyMaterialCategoryTreeData(
|
||||
majors: Array<{ id: string; name: string; minors: MixingMaterialPickerCategoryItem[] }>,
|
||||
minors: MixingMaterialPickerCategoryItem[],
|
||||
treeNodes: Recordable[],
|
||||
) {
|
||||
rawCategoryTree.value = treeNodes;
|
||||
allMajorCategories.value = majors;
|
||||
allMinorCategories.value = minors;
|
||||
|
||||
const sanitizedHidden = sanitizeMixingMaterialPickerHiddenCategoryIds(
|
||||
minors.map((item) => item.id),
|
||||
hiddenCategoryIds.value,
|
||||
);
|
||||
if (sanitizedHidden.length !== hiddenCategoryIds.value.length) {
|
||||
hiddenCategoryIds.value = sanitizedHidden;
|
||||
saveMixingMaterialPickerHiddenCategoryIds(sanitizedHidden);
|
||||
}
|
||||
|
||||
syncExpandedCategoryKeys();
|
||||
|
||||
if (!minors.length) {
|
||||
createMessage.warning('未加载到物料小类,请确认分类字典根编码 XSLMES_MATERIAL 及其下级分类已配置。');
|
||||
}
|
||||
}
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】小类设置刷新分类字典-----------
|
||||
/** 刷新分类字典:重新拉取小类列表,新增小类默认隐藏,勾选保存后展示到左侧树 */
|
||||
async function handleRefreshCategoryTree() {
|
||||
if (categoryRefreshing.value) {
|
||||
return;
|
||||
}
|
||||
const previousIds = new Set(allMinorCategories.value.map((item) => String(item.id)));
|
||||
categoryRefreshing.value = true;
|
||||
try {
|
||||
await loadMaterialCategoryTree(true);
|
||||
const newMinorIds = allMinorCategories.value
|
||||
.filter((item) => !previousIds.has(String(item.id)))
|
||||
.map((item) => String(item.id));
|
||||
if (newMinorIds.length) {
|
||||
const nextHidden = sanitizeMixingMaterialPickerHiddenCategoryIds(
|
||||
allMinorCategories.value.map((item) => item.id),
|
||||
[...hiddenCategoryIds.value.map(String), ...newMinorIds],
|
||||
);
|
||||
hiddenCategoryIds.value = nextHidden;
|
||||
createMessage.success(`已刷新,发现 ${newMinorIds.length} 个新小类,请勾选后点击保存`);
|
||||
} else {
|
||||
createMessage.success('已刷新,分类无变化');
|
||||
}
|
||||
} finally {
|
||||
categoryRefreshing.value = false;
|
||||
}
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】小类设置刷新分类字典-----------
|
||||
|
||||
function reloadTable() {
|
||||
reload();
|
||||
}
|
||||
@@ -280,6 +330,9 @@
|
||||
|
||||
function onCategorySelect(keys: KeyType[]) {
|
||||
selectedCategoryKeys.value = keys?.length ? keys : [TREE_ALL];
|
||||
if (pickerInitializing.value) {
|
||||
return;
|
||||
}
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
@@ -309,25 +362,17 @@
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
async function resolveKindForMaterial(material: Recordable, weighMode?: string) {
|
||||
function resolvePickerMaterialKind(material: Recordable) {
|
||||
const weighMode = getPickerWeighMode(material?.id);
|
||||
const minorId = material?.minorCategoryId ? String(material.minorCategoryId) : '';
|
||||
const minorName = material?.minorCategoryId_dictText || '';
|
||||
if (!minorId) {
|
||||
return resolveMixingMaterialKindForPicker(weighMode, false, minorName);
|
||||
}
|
||||
if (categoryRubberMap.value[minorId] === undefined) {
|
||||
try {
|
||||
const cat = await defHttp.get<Recordable>({ url: '/sys/category/queryById', params: { id: minorId } });
|
||||
categoryRubberMap.value[minorId] = cat?.isRubber === '1' || cat?.isRubber === 1;
|
||||
} catch {
|
||||
categoryRubberMap.value[minorId] = false;
|
||||
}
|
||||
}
|
||||
return resolveMixingMaterialKindForPicker(
|
||||
weighMode,
|
||||
categoryRubberMap.value[minorId] ? '1' : '0',
|
||||
minorName,
|
||||
);
|
||||
return resolveMixingMaterialKindForPicker(kindLookup.value, weighMode, minorId, minorName);
|
||||
}
|
||||
|
||||
function resolveKindForMaterial(material: Recordable, weighMode?: string) {
|
||||
const minorId = material?.minorCategoryId ? String(material.minorCategoryId) : '';
|
||||
const minorName = material?.minorCategoryId_dictText || '';
|
||||
return resolveMixingMaterialKindForPicker(kindLookup.value, weighMode, minorId, minorName);
|
||||
}
|
||||
|
||||
async function handleOk() {
|
||||
@@ -347,7 +392,7 @@
|
||||
}
|
||||
const weighMode = getPickerWeighMode(row.id);
|
||||
const payload: Recordable = { ...row, pickerWeighMode: weighMode };
|
||||
const materialKind = await resolveKindForMaterial(row, weighMode);
|
||||
const materialKind = resolveKindForMaterial(row, weighMode);
|
||||
applyMixingMaterialFromSelection(payload, row, materialKind);
|
||||
emit('select', payload);
|
||||
closeModal();
|
||||
@@ -399,6 +444,11 @@
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
/* 嵌套在全屏混炼示方弹窗之上,避免偶发被父弹窗遮挡 */
|
||||
.mixing-material-picker-modal-wrap {
|
||||
z-index: 1500 !important;
|
||||
}
|
||||
|
||||
/* 下拉挂到 body,避免表格 overflow 裁剪;层级高于 Modal */
|
||||
.mixing-material-picker-weigh-mode-dropdown {
|
||||
z-index: 2100 !important;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
:defaultFullscreen="true"
|
||||
wrapClassName="mixing-spec-modal-wrap"
|
||||
@register="registerModal"
|
||||
@cancel="closeNestedPickers"
|
||||
@ok="handleSubmit"
|
||||
>
|
||||
<template #title>{{ title }}</template>
|
||||
@@ -882,9 +883,18 @@ const [registerForm, { resetFields, setFieldsValue, validate, setProps }] = useF
|
||||
});
|
||||
|
||||
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A33】混炼示方主表选择弹窗-----------
|
||||
const [registerMachineModal, { openModal: openMachineModalInner }] = useModal();
|
||||
const [registerIssueNumberModal, { openModal: openIssueNumberModalInner }] = useModal();
|
||||
const [registerMixingMaterialModal, { openModal: openMixingMaterialModalInner }] = useModal();
|
||||
const [registerMachineModal, { openModal: openMachineModalInner, closeModal: closeMachineModal }] = useModal();
|
||||
const [registerIssueNumberModal, { openModal: openIssueNumberModalInner, closeModal: closeIssueNumberModal }] = useModal();
|
||||
const [registerMixingMaterialModal, { openModal: openMixingMaterialModalInner, closeModal: closeMixingMaterialModal, setModalProps: setMixingMaterialModalProps }] = useModal();
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】关闭混炼示方弹窗时同步关闭嵌套选料弹窗-----------
|
||||
function closeNestedPickers() {
|
||||
closeMixingMaterialModal();
|
||||
closeMachineModal();
|
||||
closeIssueNumberModal();
|
||||
materialPickerRow.value = null;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】关闭混炼示方弹窗时同步关闭嵌套选料弹窗-----------
|
||||
|
||||
function openMachinePicker() {
|
||||
if (!showFooter.value) {
|
||||
@@ -924,7 +934,10 @@ function openMixingMaterialPicker(row: Recordable) {
|
||||
return;
|
||||
}
|
||||
materialPickerRow.value = row;
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】选料弹窗层级高于全屏父弹窗-----------
|
||||
setMixingMaterialModalProps({ zIndex: 1500 });
|
||||
openMixingMaterialModalInner(true, { picker: true, ts: Date.now() });
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】选料弹窗层级高于全屏父弹窗-----------
|
||||
}
|
||||
|
||||
function onMixingMaterialSelect(payload: Recordable | null) {
|
||||
|
||||
Reference in New Issue
Block a user