From 0320dacaa923433c88cf0e105d5a1ad61898b6f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B8=B8=E7=86=9F=E5=90=B4=E5=BD=A6=E7=A5=96?= Date: Fri, 14 Aug 2026 13:37:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=93=81=E6=B5=81=E7=A8=8Bok?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/qms/controller/QcController.java | 15 ++ .../xujie/modules/qms/mapper/QcMapper.java | 26 +++ .../xujie/modules/qms/service/QcService.java | 10 ++ .../qms/service/impl/QcServiceImpl.java | 149 ++++++++++++++++-- src/main/resources/mapper/qms/QcMapper.xml | 77 +++++++++ 5 files changed, 263 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/xujie/modules/qms/controller/QcController.java b/src/main/java/com/xujie/modules/qms/controller/QcController.java index 8fc9b32..752b7dc 100644 --- a/src/main/java/com/xujie/modules/qms/controller/QcController.java +++ b/src/main/java/com/xujie/modules/qms/controller/QcController.java @@ -363,6 +363,21 @@ public class QcController { return R.ok(); } + /** + * @description: 复制检验模板(主表 + 检验项目 + 判定标准) + * @author: cursor-agent + * @date: 2026/8/14 + * @param: [data] + * @return: com.xujie.common.utils.R + */ + @PostMapping(value = "/templateCopy") + public R templateCopy(@RequestBody QcTemplateData data) { + QcTemplateData copyResult = qcService.templateCopy(data); + return R.ok() + .put("templateId", copyResult.getTemplateId()) + .put("templateName", copyResult.getTemplateName()); + } + /** * @description: 删除模板 * @author: fengyuan_yang diff --git a/src/main/java/com/xujie/modules/qms/mapper/QcMapper.java b/src/main/java/com/xujie/modules/qms/mapper/QcMapper.java index 14aa00b..69f6069 100644 --- a/src/main/java/com/xujie/modules/qms/mapper/QcMapper.java +++ b/src/main/java/com/xujie/modules/qms/mapper/QcMapper.java @@ -98,8 +98,34 @@ public interface QcMapper { void templateUpdate(QcTemplateData data); + /** + * 按模板主键查询模板主记录(复制源数据使用)。 + */ + QcTemplateData selectTemplateMainForCopy(QcTemplateData data); + List templateDetailsSearch(QcTemplateData data); + /** + * 复制模板项目明细(qc_template_detailed)到新模板编码。 + */ + int copyTemplateDetails(@Param("site") String site, + @Param("buNo") String buNo, + @Param("sourceTemplateId") String sourceTemplateId, + @Param("targetTemplateId") String targetTemplateId); + + /** + * 复制模板判定标准(qc_inspection_standards)到新模板编码。 + */ + int copyTemplateInspectionStandards(@Param("site") String site, + @Param("buNo") String buNo, + @Param("sourceTemplateId") String sourceTemplateId, + @Param("targetTemplateId") String targetTemplateId); + + /** + * 统计指定物理表是否存在(用于兼容不同库版本的表结构差异)。 + */ + Integer countBaseTableByName(@Param("tableName") String tableName); + QcTemplateData selectItemDetails(QcTemplateData data); void addItemDetails(QcTemplateData data); diff --git a/src/main/java/com/xujie/modules/qms/service/QcService.java b/src/main/java/com/xujie/modules/qms/service/QcService.java index c8d2d34..afe854a 100644 --- a/src/main/java/com/xujie/modules/qms/service/QcService.java +++ b/src/main/java/com/xujie/modules/qms/service/QcService.java @@ -73,6 +73,16 @@ public interface QcService { void templateUpdate(QcTemplateData data); + /** + * 复制检验模板(主表 + 模板明细 + 判定标准)。 + * + * 约束说明: + * 1) 仅根据请求参数中的 site/buNo/templateId 定位源模板; + * 2) 复制后自动生成新的模板编码,模板名称固定为“源模板名_复制”; + * 3) 复制返回新模板的关键信息,便于前端提示用户。 + */ + QcTemplateData templateCopy(QcTemplateData data); + List templateDetailsSearch(QcTemplateData data); void addItemDetails(QcTemplateData data); diff --git a/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java b/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java index 0af3b5d..1d5ae13 100644 --- a/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java +++ b/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java @@ -71,6 +71,7 @@ import java.util.stream.Collectors; public class QcServiceImpl implements QcService { private static final String TEMPLATE_SUPPLIER_WILDCARD = "*"; private static final String PART_ATTRIBUTE_TYPE_MATERIAL = "A"; + private static final String TABLE_QC_INSPECTION_STANDARDS = "qc_inspection_standards"; //记录日志使用 private static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class); @@ -510,20 +511,9 @@ public class QcServiceImpl implements QcService { QcSiteBuHelper.resolveSiteAndBu(data.getBu(), data::setSite, data::setBuNo); // 获取编码 String templateNo = qcMapper.getTemplateNo(data); - if ("101".equals(data.getInspectionTypeNo()) || "102".equals(data.getInspectionTypeNo()) || "103".equals(data.getInspectionTypeNo()) || "104".equals(data.getInspectionTypeNo())) { - data.setTemplateId("IPQC-" + templateNo); - } else if ("105".equals(data.getInspectionTypeNo())) { - data.setTemplateId("IQC-" + templateNo); - } else if ("106".equals(data.getInspectionTypeNo())) { - data.setTemplateId("FAI-" + templateNo); - } else if ("107".equals(data.getInspectionTypeNo())) { - data.setTemplateId("FQC-" + templateNo); - } else if ("108".equals(data.getInspectionTypeNo())) { - data.setTemplateId("PQC-" + templateNo); - } else if ("GX".equals(data.getInspectionTypeNo())) { - data.setTemplateId("GX-" + templateNo); - }else if ("***".equals(data.getInspectionTypeNo())) { - data.setTemplateId("PF-" + templateNo); + data.setTemplateId(buildTemplateIdByInspectionType(data.getInspectionTypeNo(), templateNo)); + if (StringUtils.isBlank(data.getTemplateId())) { + throw new RuntimeException("检验类型不支持生成模板编码,请检查检验类型配置!"); } List checkTemplateOnlyOne = qcMapper.checkTemplateOnlyOne(data); if (!checkTemplateOnlyOne.isEmpty()) { @@ -533,6 +523,137 @@ public class QcServiceImpl implements QcService { qcMapper.templateSave(data); } + /** + * 复制检验模板(主表 + 模板项目明细 + 判定标准)。 + * + * 业务意图: + * 1) 在“模板维护”页提供一键复制,快速产出可调整的新模板; + * 2) 新模板编码按检验类型重新生成,避免主键冲突; + * 3) 新模板名称固定“源模板名_复制”,便于用户识别复制来源。 + * + * 关键输入: + * - site/buNo/templateId:唯一定位源模板; + * - createBy/updateBy:记录复制操作人。 + * + * 边界与失败处理: + * - 源模板不存在时直接抛错,防止复制脏数据; + * - 模板编码生成失败时抛错,避免写入无效主键; + * - 明细/标准复制均放在同一事务中,任一步失败全部回滚。 + */ + @Override + @Transactional + public QcTemplateData templateCopy(QcTemplateData data) { + if (data == null) { + throw new RuntimeException("复制模板请求体不能为空!"); + } + if (StringUtils.isBlank(data.getSite()) || StringUtils.isBlank(data.getBuNo()) || StringUtils.isBlank(data.getTemplateId())) { + throw new RuntimeException("复制模板缺少关键参数(site/buNo/templateId)!"); + } + String submitBy = StringUtils.trimToEmpty(StringUtils.defaultIfBlank(data.getUpdateBy(), data.getCreateBy())); + if (StringUtils.isBlank(submitBy)) { + throw new RuntimeException("复制模板缺少操作人信息(createBy/updateBy)!"); + } + + // 仅以请求参数中的 site/buNo/templateId 查询源模板,避免读取登录态兜底导致跨站点误复制。 + QcTemplateData sourceTemplate = qcMapper.selectTemplateMainForCopy(data); + if (sourceTemplate == null) { + throw new RuntimeException("源检验模板不存在,请刷新后重试!"); + } + + // 生成新模板编码:同站点同BU同检验类型下按现有规则自增。 + String templateNo = qcMapper.getTemplateNo(sourceTemplate); + String newTemplateId = buildTemplateIdByInspectionType(sourceTemplate.getInspectionTypeNo(), templateNo); + if (StringUtils.isBlank(newTemplateId)) { + throw new RuntimeException("检验类型不支持生成模板编码,请检查源模板配置!"); + } + + // 组装新模板主记录:保留源模板业务字段,仅替换模板编码、模板名称、操作人。 + QcTemplateData targetTemplate = new QcTemplateData(); + targetTemplate.setSite(sourceTemplate.getSite()); + targetTemplate.setBuNo(sourceTemplate.getBuNo()); + targetTemplate.setTemplateId(newTemplateId); + targetTemplate.setTemplateName(buildCopiedTemplateName(sourceTemplate.getTemplateName())); + targetTemplate.setTemplateRemark(sourceTemplate.getTemplateRemark()); + targetTemplate.setTemplateType(sourceTemplate.getTemplateType()); + targetTemplate.setTemplateVersion(sourceTemplate.getTemplateVersion()); + targetTemplate.setSamplingProgrammeNo(sourceTemplate.getSamplingProgrammeNo()); + targetTemplate.setInspectionTypeNo(sourceTemplate.getInspectionTypeNo()); + targetTemplate.setSamplingLevelNo(sourceTemplate.getSamplingLevelNo()); + targetTemplate.setInspectionCycle(sourceTemplate.getInspectionCycle()); + targetTemplate.setAql(sourceTemplate.getAql()); + targetTemplate.setAc(sourceTemplate.getAc()); + targetTemplate.setRe(sourceTemplate.getRe()); + targetTemplate.setDefaultSamplingQuantity(sourceTemplate.getDefaultSamplingQuantity()); + targetTemplate.setDefaultSamplingProportion(sourceTemplate.getDefaultSamplingProportion()); + targetTemplate.setTemplateSort(sourceTemplate.getTemplateSort()); + targetTemplate.setOperation(sourceTemplate.getOperation()); + targetTemplate.setCreateBy(submitBy); + targetTemplate.setUpdateBy(submitBy); + + // 1) 先落主表;2) 再复制项目明细;3) 再复制判定标准,保证结构完整。 + qcMapper.templateSave(targetTemplate); + qcMapper.copyTemplateDetails(targetTemplate.getSite(), targetTemplate.getBuNo(), sourceTemplate.getTemplateId(), targetTemplate.getTemplateId()); + // 兼容库差异: + // 某些环境不存在 qc_inspection_standards(历史库/轻量库),此时只复制主表与项目明细,避免SQL异常中断复制流程。 + if (isBaseTableExists(TABLE_QC_INSPECTION_STANDARDS)) { + qcMapper.copyTemplateInspectionStandards(targetTemplate.getSite(), targetTemplate.getBuNo(), sourceTemplate.getTemplateId(), targetTemplate.getTemplateId()); + } else { + log.warn("模板复制跳过判定标准复制:表{}不存在,site={}, buNo={}, sourceTemplateId={}, targetTemplateId={}", + TABLE_QC_INSPECTION_STANDARDS, + targetTemplate.getSite(), + targetTemplate.getBuNo(), + sourceTemplate.getTemplateId(), + targetTemplate.getTemplateId()); + } + return targetTemplate; + } + + /** + * 判断指定基础表是否存在。 + * 作用: + * 1) 在跨环境发布时避免“对象名无效”导致业务失败; + * 2) 只用于读取元数据,不涉及任何写操作。 + * + * @param tableName 物理表名(不带 schema) + * @return true=存在,false=不存在 + */ + private boolean isBaseTableExists(String tableName) { + Integer tableCount = qcMapper.countBaseTableByName(tableName); + return tableCount != null && tableCount > 0; + } + + /** + * 按检验类型生成模板编码前缀。 + * 入参模板号 templateNo 应由 SQL 自增逻辑生成。 + */ + private String buildTemplateIdByInspectionType(String inspectionTypeNo, String templateNo) { + if ("101".equals(inspectionTypeNo) || "102".equals(inspectionTypeNo) || "103".equals(inspectionTypeNo) || "104".equals(inspectionTypeNo)) { + return "IPQC-" + templateNo; + } else if ("105".equals(inspectionTypeNo)) { + return "IQC-" + templateNo; + } else if ("106".equals(inspectionTypeNo)) { + return "FAI-" + templateNo; + } else if ("107".equals(inspectionTypeNo)) { + return "FQC-" + templateNo; + } else if ("108".equals(inspectionTypeNo)) { + return "PQC-" + templateNo; + } else if ("GX".equals(inspectionTypeNo)) { + return "GX-" + templateNo; + } else if ("***".equals(inspectionTypeNo)) { + return "PF-" + templateNo; + } + return ""; + } + + /** + * 复制模板命名规则: + * - 标准格式:源模板名称 + "_复制"; + * - 若源模板名为空,则退化为 "_复制",避免出现 null 文本。 + */ + private String buildCopiedTemplateName(String sourceTemplateName) { + return StringUtils.trimToEmpty(sourceTemplateName) + "_复制"; + } + /** * 修改模板 **/ diff --git a/src/main/resources/mapper/qms/QcMapper.xml b/src/main/resources/mapper/qms/QcMapper.xml index 20ac71b..cf12d91 100644 --- a/src/main/resources/mapper/qms/QcMapper.xml +++ b/src/main/resources/mapper/qms/QcMapper.xml @@ -481,6 +481,83 @@ WHERE template_id = #{templateId} AND site = #{site} and bu_no = #{buNo} + + + + + + INSERT INTO qc_template_detailed + (template_id, ItemNo, default_value, max_value, min_value, site, bu_no, order_id, object_id) + SELECT + #{targetTemplateId}, + ItemNo, + default_value, + max_value, + min_value, + site, + bu_no, + order_id, + object_id + FROM qc_template_detailed + WHERE site = #{site} + AND bu_no = #{buNo} + AND template_id = #{sourceTemplateId} + + + + + INSERT INTO qc_inspection_standards + (site, bu_no, template_id, item_no, default_value, min_value, max_value, condition, collection_source, seq_no) + SELECT + site, + bu_no, + #{targetTemplateId}, + item_no, + default_value, + min_value, + max_value, + condition, + collection_source, + seq_no + FROM qc_inspection_standards + WHERE site = #{site} + AND bu_no = #{buNo} + AND template_id = #{sourceTemplateId} + + + + +