diff --git a/jeecg-boot/db/mes-fix-rubber-category-visible.sql b/jeecg-boot/db/mes-fix-rubber-category-visible.sql new file mode 100644 index 0000000..85f2004 --- /dev/null +++ b/jeecg-boot/db/mes-fix-rubber-category-visible.sql @@ -0,0 +1,64 @@ +-- 修复:胶料分类字典(XSLMES_RUBBER)数据库有数据但页面不展示 +-- 场景:开启多租户后,sys_category 的 tenant_id 与当前登录租户不一致/为空 +SET NAMES utf8mb4; + +-- 1) 目标租户:默认取 admin 用户租户;若为空则回退到 0 +SET @target_tenant_id = ( + SELECT COALESCE(tenant_id, 0) + FROM sys_user + WHERE username = 'admin' + ORDER BY create_time ASC + LIMIT 1 +); +SET @target_tenant_id = IFNULL(@target_tenant_id, 0); + +-- 2) 定位根分类编码 +SET @rubber_code = 'XSLMES_RUBBER'; + +-- 若根节点不存在则补一个最小根节点(避免前端 pcode 查询直接失败) +INSERT INTO sys_category (id, pid, name, code, has_child, tenant_id, create_by, create_time, update_by, update_time) +SELECT '1994000000000000001', '0', 'MES胶料分类', @rubber_code, '1', @target_tenant_id, 'admin', NOW(), 'admin', NOW() +FROM dual +WHERE NOT EXISTS ( + SELECT 1 FROM sys_category WHERE code = @rubber_code +); + +SET @rubber_root_id = ( + SELECT id + FROM sys_category + WHERE code = @rubber_code + ORDER BY create_time ASC + LIMIT 1 +); + +-- 3) 若根节点存在,统一修复租户与父子标记 +UPDATE sys_category +SET tenant_id = @target_tenant_id +WHERE id = @rubber_root_id; + +UPDATE sys_category +SET tenant_id = @target_tenant_id +WHERE pid = @rubber_root_id; + +-- 根节点是否有子节点,按真实数据回写 +UPDATE sys_category +SET has_child = CASE + WHEN EXISTS (SELECT 1 FROM (SELECT id FROM sys_category WHERE pid = @rubber_root_id LIMIT 1) t) THEN '1' + ELSE '0' +END +WHERE id = @rubber_root_id; + +-- 子节点统一标记为无子(当前这批分类通常为叶子) +UPDATE sys_category +SET has_child = '0' +WHERE pid = @rubber_root_id; + +-- 4) 结果检查(执行后看返回) +SELECT 'ROOT' AS level_tag, id, pid, code, name, tenant_id, has_child +FROM sys_category +WHERE id = @rubber_root_id +UNION ALL +SELECT 'CHILD' AS level_tag, id, pid, code, name, tenant_id, has_child +FROM sys_category +WHERE pid = @rubber_root_id +ORDER BY level_tag, code; diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java index c35a80b..55ef2ff 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java @@ -785,40 +785,46 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl byCodeWrapper = new LambdaQueryWrapper() + .eq(MesMaterial::getMaterialCode, specCode) + .and(w -> w.eq(MesMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMaterial::getDelFlag)); + appendPhaseMatch(byCodeWrapper, materialPhase); MesMaterial byCode = mesMaterialService.getOne( - new LambdaQueryWrapper() - .eq(MesMaterial::getMaterialCode, specCode) - .and(w -> w.eq(MesMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMaterial::getDelFlag)) - .last("limit 1")); + byCodeWrapper.last("limit 1")); if (byCode != null) { return byCode; } + LambdaQueryWrapper byNameWrapper = new LambdaQueryWrapper() + .eq(MesMaterial::getMaterialName, specCode) + .and(w -> w.eq(MesMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMaterial::getDelFlag)); + appendPhaseMatch(byNameWrapper, materialPhase); return mesMaterialService.getOne( - new LambdaQueryWrapper() - .eq(MesMaterial::getMaterialName, specCode) - .and(w -> w.eq(MesMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMaterial::getDelFlag)) - .last("limit 1")); + byNameWrapper.last("limit 1")); + } + + private void appendPhaseMatch(LambdaQueryWrapper wrapper, String materialPhase) { + if (wrapper == null || StringUtils.isBlank(materialPhase)) { + return; + } + wrapper.and(w -> w.eq(MesMaterial::getMaterialPhase, materialPhase) + .or() + .isNull(MesMaterial::getMaterialPhase) + .or() + .eq(MesMaterial::getMaterialPhase, "")); + } + + private String resolveGeneratedMaterialPhase(MesXslFormulaMixingGenerateRowVO row) { + if (row == null) { + return null; + } + if ("Q".equalsIgnoreCase(resolveMixingMaterialStep(row))) { + return "F"; + } + if (row.getASegmentIndex() != null && row.getASegmentIndex() > 0) { + return "B" + row.getASegmentIndex(); + } + if (row.getStageIndex() != null && row.getStageIndex() > 0) { + return "B" + row.getStageIndex(); + } + return "B1"; + } + + private String buildGeneratedRubberMaterialName(MesXslFormulaMixingGenerateRowVO row, String rubberName) { + String baseName = StringUtils.defaultString(rubberName).trim(); + if (StringUtils.isBlank(baseName) && row != null && StringUtils.isNotBlank(row.getSpecCode())) { + baseName = row.getSpecCode().trim(); + } + String phase = resolveGeneratedMaterialPhase(row); + if (StringUtils.isBlank(phase)) { + return baseName; + } + return phase + baseName; } //update-end---author:cursor ---date:20260601 for:【XSLMES-20260601-A62】生成混炼示方改为同步B/F段胶至胶料信息----------- @@ -947,9 +1031,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl 0) { return Math.min(row.getStageIndex(), 7); } - String specCode = row != null ? row.getSpecCode() : null; - if (StringUtils.isNotBlank(specCode)) { - Matcher matcher = Pattern.compile("(?i)B(\\d+)").matcher(specCode.trim()); + String normalizedSpecCode = row == null ? "" : StringUtils.trimToEmpty(row.getSpecCode()); + if (StringUtils.isNotEmpty(normalizedSpecCode)) { + Matcher matcher = Pattern.compile("(?i)B(\\d+)").matcher(normalizedSpecCode); if (matcher.find()) { return Math.min(Integer.parseInt(matcher.group(1)), 7); } @@ -965,8 +1049,8 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl categoryIdCache) { String stepFilter = StringUtils.isNotBlank(materialStep) ? materialStep.trim().toUpperCase() : "A"; List materials = new ArrayList<>(); - int sort = 0; if ("Q".equals(stepFilter)) { //update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】F段加入最后一段B炼好胶料一条再加Q配合剂----------- String rubberName = resolveRubberName(formula); diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRawMaterialInspectRecordServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRawMaterialInspectRecordServiceImpl.java index 831d54d..d1db6d6 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRawMaterialInspectRecordServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRawMaterialInspectRecordServiceImpl.java @@ -148,8 +148,7 @@ public class MesXslRawMaterialInspectRecordServiceImpl if (lineList == null || lineList.isEmpty()) { throw new JeecgBootException("请至少录入一条检验结果"); } - - boolean allPass = true; + boolean hasAnyDetailUpdated = false; for (MesXslRawMaterialInspectRecordLine line : lineList) { if (StringUtils.isBlank(line.getId())) { throw new JeecgBootException("明细ID不能为空,请刷新后重试"); @@ -158,6 +157,15 @@ public class MesXslRawMaterialInspectRecordServiceImpl if (dbLine == null || !recordId.equals(dbLine.getRecordId())) { throw new JeecgBootException("明细不存在或不属于当前送检记录"); } + // 已录入(非待检)明细不允许再次录入,防止重复覆盖。 + String dbPassFlag = normalize(dbLine.getPassFlag()); + if (!STATUS_PENDING.equals(dbPassFlag)) { + throw new JeecgBootException("检验项目【" + dbLine.getInspectItemName() + "】已录入,不能重复录入"); + } + // 允许分次录入:本次未填检验值的明细跳过,不改该行状态。 + if (line.getInspectValue() == null) { + continue; + } String passFlag = evaluatePassFlag( line.getInspectValue(), @@ -168,20 +176,37 @@ public class MesXslRawMaterialInspectRecordServiceImpl dbLine.setInspectValue(line.getInspectValue()); dbLine.setPassFlag(passFlag); recordLineMapper.updateById(dbLine); + hasAnyDetailUpdated = true; + } + if (!hasAnyDetailUpdated) { + throw new JeecgBootException("请至少录入一条检验值后再保存"); + } + + List allDbLines = selectLinesByRecordId(recordId); + boolean allCompleted = true; + boolean allPass = true; + for (MesXslRawMaterialInspectRecordLine dbLine : allDbLines) { + String passFlag = normalize(dbLine.getPassFlag()); + if (STATUS_PENDING.equals(passFlag) || StringUtils.isBlank(passFlag)) { + allCompleted = false; + continue; + } if (!STATUS_PASS.equals(passFlag)) { allPass = false; } } - record.setInspectStatus(allPass ? STATUS_PASS : STATUS_FAIL); - record.setResultTime(new Date()); - this.updateById(record); - // 判定完成后回写原材料卡片检测结果 - if (StringUtils.isNotBlank(record.getRawMaterialCardId())) { - MesXslRawMaterialCard card = new MesXslRawMaterialCard(); - card.setId(record.getRawMaterialCardId()); - card.setTestResult(allPass ? CARD_TEST_RESULT_PASS : CARD_TEST_RESULT_FAIL); - rawMaterialCardService.updateById(card); + // 仅当全部明细已完成录入时,才回写主表/卡片检验状态。 + if (allCompleted) { + record.setInspectStatus(allPass ? STATUS_PASS : STATUS_FAIL); + record.setResultTime(new Date()); + this.updateById(record); + if (StringUtils.isNotBlank(record.getRawMaterialCardId())) { + MesXslRawMaterialCard card = new MesXslRawMaterialCard(); + card.setId(record.getRawMaterialCardId()); + card.setTestResult(allPass ? CARD_TEST_RESULT_PASS : CARD_TEST_RESULT_FAIL); + rawMaterialCardService.updateById(card); + } } } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/controller/MesMaterialController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/controller/MesMaterialController.java index ab4090a..47e7497 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/controller/MesMaterialController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/controller/MesMaterialController.java @@ -33,8 +33,12 @@ public class MesMaterialController extends JeecgController queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap()); + if (onlySales != null && onlySales == 1) { + queryWrapper.and(w -> w.isNull("material_phase").or().eq("material_phase", "")); + } IPage pageList = mesMaterialService.page(new Page<>(pageNo, pageSize), queryWrapper); return Result.OK(pageList); } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/entity/MesMaterial.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/entity/MesMaterial.java index 8fc88c8..b5c0874 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/entity/MesMaterial.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/entity/MesMaterial.java @@ -74,6 +74,8 @@ public class MesMaterial implements Serializable { @Excel(name = "胶料客户", width = 15, dictTable = "mes_xsl_customer", dicText = "customer_name", dicCode = "id") @Dict(dictTable = "mes_xsl_customer", dicText = "customer_name", dicCode = "id") private String customerId; + @Excel(name = "物料阶段", width = 12) + private String materialPhase; @Excel(name = "使用状态", width = 10, replace = {"使用中_1", "停用_0"}) private Integer enableFlag; @Excel(name = "是否为特种胶", width = 12, replace = {"是_1", "否_0"}) diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_109__mes_material_phase.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_109__mes_material_phase.sql new file mode 100644 index 0000000..f1ac393 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_109__mes_material_phase.sql @@ -0,0 +1,11 @@ +-- mes_material 新增物料阶段字段(销售物料为空,生产自动生成为 Bn/F) +SET NAMES utf8mb4; + +SET @db = DATABASE(); + +SET @sql = IF( + (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_material' AND COLUMN_NAME = 'material_phase') = 0, + 'ALTER TABLE `mes_material` ADD COLUMN `material_phase` varchar(16) DEFAULT NULL COMMENT ''物料阶段(销售为空,生产为B1/B2.../F)'' AFTER `customer_id`', + 'SELECT 1' +); +PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; diff --git a/jeecgboot-vue3/src/views/mes/material/modules/MesMaterialSelectModal.vue b/jeecgboot-vue3/src/views/mes/material/modules/MesMaterialSelectModal.vue index c2af658..13da17b 100644 --- a/jeecgboot-vue3/src/views/mes/material/modules/MesMaterialSelectModal.vue +++ b/jeecgboot-vue3/src/views/mes/material/modules/MesMaterialSelectModal.vue @@ -16,6 +16,7 @@ const { createMessage } = useMessage(); const selectedRow = ref(null); + const onlySales = ref(false); const [registerTable, { reload, getSelectRowKeys, getSelectRows, setSelectedRowKeys, clearSelectedRowKeys }] = useTable({ api: materialList, @@ -33,6 +34,7 @@ beforeFetch: (params) => ({ ...params, enableFlag: params.enableFlag ?? 1, + onlySales: onlySales.value ? 1 : undefined, }), rowSelection: { type: 'radio', @@ -46,6 +48,7 @@ const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { selectedRow.value = null; + onlySales.value = !!data?.onlySales; clearSelectedRowKeys?.(); setModalProps({ confirmLoading: false }); const materialId = data?.materialId as string | undefined; diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue index fe89e22..c1ab527 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue @@ -831,7 +831,7 @@ if (!showFooterFlag.value) { return; } - openRubberMaterialModalInner(true, { materialId: rubberMaterialPickerId.value || '' }); + openRubberMaterialModalInner(true, { materialId: rubberMaterialPickerId.value || '', onlySales: true }); } function openIssueNumberPicker() { diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslRawMaterialInspectRecord/MesXslRawMaterialInspectRecord.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslRawMaterialInspectRecord/MesXslRawMaterialInspectRecord.data.ts index 16b385d..5f3e002 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslRawMaterialInspectRecord/MesXslRawMaterialInspectRecord.data.ts +++ b/jeecgboot-vue3/src/views/xslmes/mesXslRawMaterialInspectRecord/MesXslRawMaterialInspectRecord.data.ts @@ -68,7 +68,12 @@ export const lineJVxeColumns: JVxeColumn[] = [ key: 'inspectValue', type: JVxeTypes.inputNumber, width: 120, - validateRules: [{ required: true, message: '${title}必填' }], + props: { + isDisabledCell: ({ row }) => { + const passFlag = String(row?.passFlag ?? ''); + return passFlag !== '' && passFlag !== '0'; + }, + }, }, { title: '判定', diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslRawMaterialInspectRecord/modules/MesXslRawMaterialInspectRecordResultModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslRawMaterialInspectRecord/modules/MesXslRawMaterialInspectRecordResultModal.vue index e41801b..b52d012 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslRawMaterialInspectRecord/modules/MesXslRawMaterialInspectRecordResultModal.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslRawMaterialInspectRecord/modules/MesXslRawMaterialInspectRecordResultModal.vue @@ -114,15 +114,14 @@ } try { const lineRef = lineTableRef.value as any; - if (lineRef?.validateTable) { - const err = await lineRef.validateTable(); - if (err) { - createMessage.warning('请完善检验值'); - return; - } - } const tableData = (lineRef?.getTableData?.() || []) as Recordable[]; - const lineList = tableData.map((item) => ({ + const editableRows = tableData.filter((item) => String(item?.passFlag ?? '0') === '0'); + const hasInput = editableRows.some((item) => item.inspectValue !== null && item.inspectValue !== undefined && item.inspectValue !== ''); + if (!hasInput) { + createMessage.warning('请至少录入一条检验值'); + return; + } + const lineList = editableRows.map((item) => ({ id: item.id, inspectValue: item.inspectValue, }));