package com.ruoyi.quality.controller; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.quality.dto.QualityMetricBindingDto; import com.ruoyi.quality.dto.QualityMetricDto; import com.ruoyi.quality.mapper.QualityTestStandardBindingMapper; import com.ruoyi.quality.mapper.QualityTestStandardParamMapper; import com.ruoyi.quality.pojo.QualityTestStandard; import com.ruoyi.quality.pojo.QualityTestStandardBinding; import com.ruoyi.quality.pojo.QualityTestStandardParam; import com.ruoyi.quality.service.IQualityTestStandardService; import com.ruoyi.quality.service.QualityTestStandardBindingService; import com.ruoyi.quality.service.QualityTestStandardParamService; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; import java.util.List; import java.util.stream.Collectors; /** * 按产品维护检测指标。 * * 前端的“指标维护”页面以产品为入口,本接口将产品、检测标准与标准参数的 * 三层数据结构封装为页面所需的单层指标操作,并按检验类别/工序隔离指标池。 */ @RestController @RequestMapping("/quality/qualityMetric") @RequiredArgsConstructor public class QualityMetricController { private static final int INSPECT_TYPE_PROCESS = 1; private final QualityTestStandardParamMapper qualityTestStandardParamMapper; private final QualityTestStandardParamService qualityTestStandardParamService; private final QualityTestStandardBindingService qualityTestStandardBindingService; private final IQualityTestStandardService qualityTestStandardService; private final QualityTestStandardBindingMapper qualityTestStandardBindingMapper; @GetMapping("/listPage") public AjaxResult listPage(Page page, @RequestParam("productId") Long productId, @RequestParam(value = "inspectType", required = false) Integer inspectType, @RequestParam(value = "processId", required = false) Long processId) { IPage result = qualityTestStandardParamMapper .selectPageByProductId(page, productId, inspectType, processId); return AjaxResult.success(result); } @GetMapping("/product/{productId}") public AjaxResult listByProduct(@PathVariable("productId") Long productId, @RequestParam(value = "inspectType", required = false) Integer inspectType, @RequestParam(value = "process", required = false) String process) { return AjaxResult.success(qualityTestStandardParamMapper .selectListByProductId(productId, inspectType, process)); } @PostMapping("/add") @Transactional(rollbackFor = Exception.class) public AjaxResult add(@RequestBody QualityMetricDto metric) { normalizeInspectType(metric); String validationMessage = validateMetric(metric, true); if (validationMessage != null) { return AjaxResult.error(validationMessage); } Long testStandardId = getOrCreateTestStandard(metric.getProductId(), metric.getInspectType(), metric.getProcessId()); QualityTestStandardParam parameter = copyEditableFields(metric, new QualityTestStandardParam()); parameter.setTestStandardId(testStandardId); if (!qualityTestStandardParamService.save(parameter)) { throw new ServiceException("保存检测指标失败"); } return AjaxResult.success(true); } @PostMapping("/update") public AjaxResult update(@RequestBody QualityMetricDto metric) { String validationMessage = validateMetric(metric, false); if (validationMessage != null) { return AjaxResult.error(validationMessage); } if (metric.getId() == null) { return AjaxResult.error("指标ID不能为空"); } QualityTestStandardParam parameter = qualityTestStandardParamService.getById(metric.getId()); if (parameter == null) { return AjaxResult.error("检测指标不存在"); } copyEditableFields(metric, parameter); if (!qualityTestStandardParamService.updateById(parameter)) { throw new ServiceException("修改检测指标失败"); } return AjaxResult.success(true); } @DeleteMapping("/del") public AjaxResult delete(@RequestBody List ids) { if (CollectionUtils.isEmpty(ids)) { return AjaxResult.error("请选择至少一条数据"); } if (!qualityTestStandardParamService.removeBatchByIds(ids)) { throw new ServiceException("删除检测指标失败"); } return AjaxResult.success(true); } @PostMapping("/export") public void export(HttpServletResponse response, @RequestParam("productId") Long productId, @RequestParam(value = "inspectType", required = false) Integer inspectType, @RequestParam(value = "process", required = false) String process) { List list = qualityTestStandardParamMapper .selectListByProductId(productId, inspectType, process); ExcelUtil util = new ExcelUtil<>(QualityTestStandardParam.class); util.exportExcel(response, list, "检测指标"); } /** * 查询全部检测标准,供“指标绑定”页面选择。 */ @GetMapping("/standardList") public AjaxResult standardList() { return AjaxResult.success(qualityTestStandardService.list( Wrappers.lambdaQuery() .orderByDesc(QualityTestStandard::getId))); } /** * 查询产品已绑定的检测标准。 */ @GetMapping("/bindingList") public AjaxResult bindingList(@RequestParam("productId") Long productId) { return AjaxResult.success(qualityTestStandardBindingMapper.selectBindingByProductId(productId)); } /** * 绑定产品与检测标准。 */ @PostMapping("/binding") public AjaxResult bind(@RequestBody QualityMetricBindingDto binding) { if (binding.getProductId() == null) { return AjaxResult.error("请先选择产品"); } if (binding.getTestStandardId() == null) { return AjaxResult.error("请选择检测标准"); } long exists = qualityTestStandardBindingService.count( Wrappers.lambdaQuery() .eq(QualityTestStandardBinding::getProductId, binding.getProductId()) .eq(QualityTestStandardBinding::getTestStandardId, binding.getTestStandardId())); if (exists > 0) { return AjaxResult.error("该标准已绑定到此产品"); } QualityTestStandardBinding entity = new QualityTestStandardBinding(); entity.setProductId(binding.getProductId()); entity.setTestStandardId(binding.getTestStandardId()); if (!qualityTestStandardBindingService.save(entity)) { throw new ServiceException("绑定检测标准失败"); } return AjaxResult.success(true); } /** * 解除产品与检测标准的绑定。 */ @DeleteMapping("/binding") public AjaxResult unbind(@RequestBody List ids) { if (CollectionUtils.isEmpty(ids)) { return AjaxResult.error("请选择至少一条数据"); } if (!qualityTestStandardBindingService.removeBatchByIds(ids)) { throw new ServiceException("解除绑定失败"); } return AjaxResult.success(true); } private void normalizeInspectType(QualityMetricDto metric) { if (metric != null && metric.getInspectType() == null) { metric.setInspectType(0); } } /** * 查找或创建与“产品 + 检验类别 + 工序”匹配的检测标准,并建立产品绑定。 */ private Long getOrCreateTestStandard(Long productId, Integer inspectType, Long processId) { int type = inspectType == null ? 0 : inspectType; List bindings = qualityTestStandardBindingService.list( Wrappers.lambdaQuery() .eq(QualityTestStandardBinding::getProductId, productId) .orderByAsc(QualityTestStandardBinding::getId)); if (!bindings.isEmpty()) { List standardIds = bindings.stream() .map(QualityTestStandardBinding::getTestStandardId) .collect(Collectors.toList()); com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() .in(QualityTestStandard::getId, standardIds) .eq(QualityTestStandard::getInspectType, type); // 仅过程检验按工序区分标准,原材料/出厂检验忽略工序 if (type == INSPECT_TYPE_PROCESS && processId != null) { wrapper.eq(QualityTestStandard::getProcessId, processId.intValue()); } QualityTestStandard matched = qualityTestStandardService.getOne( wrapper.orderByAsc(QualityTestStandard::getId).last("limit 1")); if (matched != null) { return matched.getId(); } } QualityTestStandard standard = new QualityTestStandard(); String suffix = inspectTypeSuffix(type) + (processId == null ? "" : "-" + processId); standard.setStandardNo("AUTO-" + productId + "-" + suffix); standard.setStandardName("产品检测指标-" + productId + "-" + suffix); standard.setState("1"); standard.setInspectType(type); if (processId != null) { standard.setProcessId(processId.intValue()); } if (!qualityTestStandardService.save(standard) || standard.getId() == null) { throw new ServiceException("创建产品检测标准失败"); } QualityTestStandardBinding binding = new QualityTestStandardBinding(); binding.setProductId(productId); binding.setTestStandardId(Math.toIntExact(standard.getId())); if (!qualityTestStandardBindingService.save(binding)) { throw new ServiceException("建立产品与检测标准关联失败"); } return standard.getId(); } private String inspectTypeSuffix(int inspectType) { switch (inspectType) { case 1: return "PROCESS"; case 2: return "FINAL"; default: return "RAW"; } } private String validateMetric(QualityMetricDto metric, boolean requireProduct) { if (metric == null) { return "指标数据不能为空"; } if (requireProduct && metric.getProductId() == null) { return "请先选择产品"; } if (metric.getInspectType() != null && metric.getInspectType() == INSPECT_TYPE_PROCESS && metric.getProcessId() == null) { return "过程检验请先选择工序"; } if (StringUtils.isBlank(metric.getParameterItem())) { return "指标名称不能为空"; } if (StringUtils.isBlank(metric.getUnit())) { return "单位不能为空"; } if (StringUtils.isBlank(metric.getStandardValue())) { return "标准值不能为空"; } return null; } private QualityTestStandardParam copyEditableFields(QualityMetricDto source, QualityTestStandardParam target) { target.setParameterItem(source.getParameterItem()); target.setUnit(source.getUnit()); target.setStandardValue(source.getStandardValue()); target.setControlValue(source.getControlValue()); target.setDefaultValue(source.getDefaultValue()); return target; } }