Merge remote-tracking branch '惠信/qms/develop' into qms/develop

This commit is contained in:
曹鹏飞 2026-06-14 11:21:24 +08:00
commit 2d41753566
5 changed files with 166 additions and 14 deletions

View File

@ -1,5 +1,7 @@
package com.nflg.qms.admin.controller;
import cn.hutool.core.util.StrUtil;
import com.nflg.qms.admin.service.BasdeSerialNumberControllerService;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.qo.QmsCoaReviewAddQO;
@ -8,7 +10,16 @@ import com.nflg.wms.common.pojo.qo.QmsCoaReviewSearchQO;
import com.nflg.wms.common.pojo.qo.QmsCoaReviewUpdateQO;
import com.nflg.wms.common.pojo.vo.QmsCoaReviewDetailVO;
import com.nflg.wms.common.pojo.vo.QmsCoaReviewVO;
import com.nflg.wms.common.util.VUtil;
import com.nflg.wms.repository.entity.QmsCoaReview;
import com.nflg.wms.repository.entity.QmsQcMaterial;
import com.nflg.wms.repository.entity.QmsTodoItem;
import com.nflg.wms.repository.entity.UserSupplier;
import com.nflg.wms.repository.service.IDictionaryItemService;
import com.nflg.wms.repository.service.IQmsCoaReviewService;
import com.nflg.wms.repository.service.IQmsQcMaterialService;
import com.nflg.wms.repository.service.IQmsTodoItemService;
import com.nflg.wms.repository.service.IUserSupplierService;
import com.nflg.wms.starter.BaseController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
@ -16,7 +27,9 @@ import jakarta.validation.constraints.NotNull;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
/**
* COA审核
@ -28,6 +41,21 @@ public class QmsCoaReviewController extends BaseController {
@Resource
private IQmsCoaReviewService coaReviewService;
@Resource
private IQmsTodoItemService todoItemService;
@Resource
private IDictionaryItemService dictionaryItemService;
@Resource
private IUserSupplierService userSupplierService;
@Resource
private IQmsQcMaterialService qcMaterialService;
@Resource
private BasdeSerialNumberControllerService basdeSerialNumberControllerService;
/**
* 新增COA审核记录
* 状态默认为0待提交
@ -82,6 +110,7 @@ public class QmsCoaReviewController extends BaseController {
@PostMapping("audit")
public ApiResult<Void> audit(@Valid @RequestBody QmsCoaReviewAuditQO qo) {
coaReviewService.audit(qo);
sendRejectTodoToSupplier(qo);
return ApiResult.success();
}
@ -104,4 +133,41 @@ public class QmsCoaReviewController extends BaseController {
public ApiResult<QmsCoaReviewDetailVO> detail(@NotNull(message = "ID不能为空") Long id) {
return ApiResult.success(coaReviewService.getDetail(id));
}
private void sendRejectTodoToSupplier(QmsCoaReviewAuditQO qo) {
if (!Objects.equals(qo.getStatus(), 3)) {
return;
}
QmsCoaReview review = coaReviewService.getById(qo.getId());
if (Objects.isNull(review) || Objects.isNull(review.getSupplierId())) {
return;
}
UserSupplier supplier = userSupplierService.getById(review.getSupplierId());
if (Objects.isNull(supplier) || Objects.isNull(supplier.getUserId())) {
return;
}
Long sourceTypeId = dictionaryItemService.getIdByCode("MessageType", "COANotificationSent");
VUtil.trueThrowBusinessError(Objects.isNull(sourceTypeId)).throwMessage("消息类型不存在");
QmsQcMaterial material = Objects.isNull(review.getMaterialId()) ? null : qcMaterialService.getById(review.getMaterialId());
String materialNo = material == null ? "" : material.getMaterialNo();
String title = "COA报告已驳回";
if (StrUtil.isNotBlank(materialNo)) {
title = "物料" + materialNo + "COA报告已驳回";
}
if (StrUtil.isNotBlank(review.getPurchaseNo())) {
title = title + ",采购单号:" + review.getPurchaseNo();
}
todoItemService.add(new QmsTodoItem()
.setTitle(title)
.setCode(basdeSerialNumberControllerService.generateSerialNumber(32))
.setSourceTypeId(sourceTypeId)
.setSourceId(review.getId())
.setRemark(qo.getRejectionReason())
.setCreateUserId(supplier.getUserId())
.setCreateUserName(supplier.getSupplierName())
.setCreateTime(LocalDateTime.now()));
}
}

View File

@ -135,6 +135,7 @@ public class QmsPdiComponentBindingControllerService {
getInspectionItemMap(pdiDetectionRulesId);
Set<String> boundComponentStatusKeys = new HashSet<>();
Set<String> boundComponentDedupKeys = new HashSet<>();
Map<Long, QmsPdiComponentBindingSearchVO.ImageBindingVO> boundImageMap = new LinkedHashMap<>();
for (QmsPdiComponentBinding binding : bindings) {
@ -152,12 +153,12 @@ public class QmsPdiComponentBindingControllerService {
QmsPdiComponentBindingSearchVO.ComponentBindingVO componentVO =
buildComponentVO(binding, component, inspectionItemMap.get(componentStatusKey(binding.getPdiComponentId(), binding.getStatus())));
if (binding.getStatus() == STATIC_STATUS) {
imageVO.getStaticComponents().add(componentVO);
} else {
imageVO.getDynamicComponents().add(componentVO);
}
boundComponentStatusKeys.add(componentStatusKey(binding.getPdiComponentId(), binding.getStatus()));
if (!boundComponentDedupKeys.add(componentDedupKey(componentVO.getPdiComponentName(),
componentVO.getXCoordinatePoint(), componentVO.getYCoordinatePoint()))) {
continue;
}
imageVO.getComponents().add(componentVO);
}
vo.setBoundList(boundImageMap.values().stream()
@ -386,6 +387,10 @@ public class QmsPdiComponentBindingControllerService {
return componentId + "|" + status;
}
private String componentDedupKey(String componentName, String xCoordinatePoint, String yCoordinatePoint) {
return componentName + "|" + xCoordinatePoint + "|" + yCoordinatePoint;
}
private PageData<QmsPdiComponentBindingComponentVO> pageComponents(
QmsPdiComponentBindingComponentSearchQO request,
List<QmsPdiComponentBindingComponentVO> components) {

View File

@ -99,6 +99,22 @@ public class QmsPdiDetectionRulesControllerService {
return "v" + maxVersion;
}
private void validateEnableDuplicate(String modelNo, String orderNo, Integer inspectionType,
String inspectionVersion, Long excludeId) {
var query = pdiDetectionRulesService.lambdaQuery()
.eq(QmsPdiDetectionRules::getModelNo, modelNo)
.eq(QmsPdiDetectionRules::getOrderNo, orderNo)
.eq(QmsPdiDetectionRules::getInspectionType, inspectionType)
.eq(QmsPdiDetectionRules::getInspectionVersion, inspectionVersion)
.eq(QmsPdiDetectionRules::getEnable, true);
if (excludeId != null) {
query = query.ne(QmsPdiDetectionRules::getId, excludeId);
}
if (query.exists()) {
throw new NflgException(STATE.BusinessError,
"已存在相同机型编号、销售订单号、检测类型和版本号的已启用规则,无法重复启用");
}
}
// ========================= 新增 =========================
/**
@ -111,6 +127,7 @@ public class QmsPdiDetectionRulesControllerService {
// 计算版本号取已有相同 modelNo+inspectionType+orderNo 中的最大版本若无则 v1
String version = calcVersion(request.getModelNo(), request.getInspectionType(), request.getOrderNo(), null);
validateEnableDuplicate(request.getModelNo(), request.getOrderNo(), request.getInspectionType(), version, null);
QmsPdiDetectionRules entity = new QmsPdiDetectionRules()
.setRuleNo(basdeSerialNumberControllerService.generateSerialNumber(33))
@ -121,7 +138,7 @@ public class QmsPdiDetectionRulesControllerService {
.setInspectionType(request.getInspectionType())
.setInspectionVersion(version)
.setMaintenanceEnable(false)
.setEnable(false)
.setEnable(true)
.setPublishEnable(false)
.setCreateBy(operator)
.setCreateTime(now)
@ -455,6 +472,7 @@ public class QmsPdiDetectionRulesControllerService {
"导入数据存在必填字段为空机型编号、销售订单号、检测类型、检测周期、质检员ID请检查文件");
}
String version = calcVersion(dto.getModelNo(), dto.getInspectionType(), dto.getOrderNo(), null);
validateEnableDuplicate(dto.getModelNo(), dto.getOrderNo(), dto.getInspectionType(), version, null);
QmsPdiDetectionRules entity = new QmsPdiDetectionRules()
.setRuleNo(basdeSerialNumberControllerService.generateSerialNumber(33))
.setModelNo(dto.getModelNo())
@ -464,7 +482,7 @@ public class QmsPdiDetectionRulesControllerService {
.setInspectionType(dto.getInspectionType())
.setInspectionVersion(version)
.setMaintenanceEnable(false)
.setEnable(false)
.setEnable(true)
.setPublishEnable(false)
.setCreateBy(operator)
.setCreateTime(now)

View File

@ -40,6 +40,12 @@ public class QmsPqcTaskRecordControllerService {
@Resource
private IQmsPqcInspectionRuleService pqcInspectionRuleService;
@Resource
private IQmsInspectorModelItemService inspectorModelItemService;
@Resource
private IQmsQualityInspectorService qualityInspectorService;
@Resource
private IQmsPqcInspectionPointService pqcInspectionPointService;
@ -339,6 +345,7 @@ public class QmsPqcTaskRecordControllerService {
if (Boolean.TRUE.equals(request.getIsReview())) {
queryWrapper.eq(QmsPqcTaskRecord::getStatus, (short) 3)
.eq(QmsPqcTaskRecord::getReviewerId, UserUtil.getUserId())
.orderByDesc(QmsPqcTaskRecord::getCreateTime);
} else if (Objects.equals(request.getType(), 1)) {
queryWrapper.eq(QmsPqcTaskRecord::getStatus, (short) 0)
@ -346,6 +353,7 @@ public class QmsPqcTaskRecordControllerService {
.orderByDesc(QmsPqcTaskRecord::getCreateTime);
} else if (Objects.equals(request.getType(), 0)) {
queryWrapper.in(QmsPqcTaskRecord::getStatus, (short) 1, (short) 2)
.eq(QmsPqcTaskRecord::getReviewerId, UserUtil.getUserId())
.orderByAsc(QmsPqcTaskRecord::getStatus)
.orderByDesc(QmsPqcTaskRecord::getCreateTime);
} else {
@ -1019,6 +1027,9 @@ public class QmsPqcTaskRecordControllerService {
taskRecord.setSelfTesterId(currentUserId);
taskRecord.setSelfTesterName(currentUserName);
}
User reviewer = resolvePqcReviewerUser(taskRecord.getModelNo());
taskRecord.setReviewerId(reviewer.getId());
taskRecord.setReviewerName(reviewer.getUserName());
// 自检提交状态改为1待复核
taskRecord.setStatus((short) 1);
} else {
@ -1031,6 +1042,11 @@ public class QmsPqcTaskRecordControllerService {
}
pqcTaskRecordService.updateById(taskRecord);
if (!hasReviewContent) {
sendPqcReviewTodoMessage(taskRecord, currentUserId, currentUserName, now);
} else {
markPqcReviewTodoDone(taskRecord.getId(), taskRecord.getReviewerId(), currentUserId, currentUserName, now);
}
// 6. 同步生成工单仅当任务总体不合格时才额外生成重检任务
Map<Long, Long> detailIdMap = getTaskDetailIdMap(taskRecord.getId());
List<QmsPqcUnqualifiedItemVO> unqualifiedItems = buildUnqualifiedItems(request, detailIdMap);
@ -1623,17 +1639,60 @@ public class QmsPqcTaskRecordControllerService {
.setSourceTypeId(sourceTypeId)
.setSourceId(sourceId)
.setIsRead(false)
.setCreateUserId(createUserId)
.setCreateUserName(createUserName)
.setCreateUserId(handlerUserId)
.setCreateUserName(handlerUserName)
.setCreateTime(now)
.setUpdateUserId(createUserId)
.setUpdateUserName(createUserName)
.setUpdateTime(now);
// 通过消息服务发送
sendMessageServices.forEach(service -> service.sendSystemMessage(todoItem));
}
private User resolvePqcReviewerUser(String modelNo) {
QmsInspectorModelItem modelItem = inspectorModelItemService.lambdaQuery()
.eq(QmsInspectorModelItem::getModelNo, modelNo)
.last("LIMIT 1")
.one();
VUtil.trueThrowBusinessError(modelItem == null).throwMessage("机型未绑定PQC复核人");
QmsQualityInspector inspector = qualityInspectorService.getById(modelItem.getInspectorId());
VUtil.trueThrowBusinessError(inspector == null).throwMessage("PQC复核人不存在");
VUtil.trueThrowBusinessError(!Objects.equals(inspector.getInspectionType(), 2)).throwMessage("复核人不是PQC类型");
VUtil.trueThrowBusinessError(!Boolean.TRUE.equals(inspector.getEnable())).throwMessage("PQC复核人已禁用");
QmsQualityInspector actualInspector = inspector;
if (inspector.getChangeUserId() != null) {
actualInspector = qualityInspectorService.getById(inspector.getChangeUserId());
}
User reviewer = actualInspector == null ? null : userService.getById(actualInspector.getUserId());
VUtil.trueThrowBusinessError(reviewer == null).throwMessage("实际复核人用户不存在");
return reviewer;
}
private void sendPqcReviewTodoMessage(QmsPqcTaskRecord taskRecord, Long updateUserId, String updateUserName, LocalDateTime now) {
Long reviewTypeId = dictionaryItemService.getIdByCode("MessageType", "PQCReviewTask");
VUtil.trueThrowBusinessError(reviewTypeId == null).throwMessage("消息类型PQCReviewTask不存在");
sendTodoMessage(taskRecord.getTaskNo(), taskRecord.getReviewerId(), taskRecord.getReviewerName(),
taskRecord.getId(), reviewTypeId, updateUserId, updateUserName, now);
}
private void markPqcReviewTodoDone(Long taskId, Long reviewerId, Long updateUserId, String updateUserName, LocalDateTime now) {
Long reviewTypeId = dictionaryItemService.getIdByCode("MessageType", "PQCReviewTask");
VUtil.trueThrowBusinessError(reviewTypeId == null).throwMessage("消息类型PQCReviewTask不存在");
todoItemService.lambdaUpdate()
.set(QmsTodoItem::getIsRead, true)
.set(QmsTodoItem::getUpdateUserId, updateUserId)
.set(QmsTodoItem::getUpdateUserName, updateUserName)
.set(QmsTodoItem::getUpdateTime, now)
.eq(QmsTodoItem::getSourceTypeId, reviewTypeId)
.eq(QmsTodoItem::getSourceId, taskId)
.eq(QmsTodoItem::getCreateUserId, reviewerId)
.eq(QmsTodoItem::getIsRead, false)
.update();
}
private String buildStepKey(QmsPqcInspectionPoint point) {
String stepName = StrUtil.blankToDefault(point.getStepName(), "");
String stepDicItemId = point.getStepDicItemId() == null ? "" : point.getStepDicItemId().toString();

View File

@ -1,6 +1,7 @@
package com.nflg.wms.common.pojo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.util.ArrayList;
@ -36,13 +37,16 @@ public class QmsPdiComponentBindingSearchVO {
private String uploadImageUrl;
/**
* 静态部件列表
* 已绑定部件列表
*/
private List<ComponentBindingVO> components = new ArrayList<>();
@JsonIgnore
@Deprecated
private List<ComponentBindingVO> staticComponents = new ArrayList<>();
/**
* 动态部件列表
*/
@JsonIgnore
@Deprecated
private List<ComponentBindingVO> dynamicComponents = new ArrayList<>();
}