feat(qms-issue-ticket): 新增PDI工单创建并查询不合格检测项接口

- 新增接口createAndQueryPdiTicket,实现PDI工单创建及任务不合格检测项查询并返回
- 优化工单处理记录添加逻辑,支持按处理人分组异步新增处理记录并推送待办
- 防止针对同一任务重复创建工单,改为抛出异常提示使用追加记录接口
- 持久层查询改进,支持返回工单ID及状态判定,新增状态3表示未发起工单状态
- 将工单状态为“待流转”时自动更新为“处理中”
- 修改请求及响应类,支持处理人列表和不合格检测项的结构化管理
- 完善事件描述自动拼接逻辑,整合所有不合格检测项内容作为事件说明
This commit is contained in:
funny 2026-05-09 10:46:24 +08:00
parent e3ff8ca9ff
commit d7f5495b77
9 changed files with 265 additions and 62 deletions

View File

@ -3,16 +3,8 @@ package com.nflg.qms.admin.controller;
import com.nflg.qms.admin.service.QmsIssueTicketControllerService;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketAddQO;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketAuditQO;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketPdiAddQO;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketSearchQO;
import com.nflg.wms.common.pojo.qo.QmsPdiInitiateTicketQO;
import com.nflg.wms.common.pojo.vo.QmsIssueTicketDetailVO;
import com.nflg.wms.common.pojo.vo.QmsIssueTicketVO;
import com.nflg.wms.common.pojo.vo.QmsPdiInspectionResultVO;
import com.nflg.wms.common.pojo.vo.QmsPdiTicketDetailVO;
import com.nflg.wms.common.pojo.vo.QmsPdiTicketMyDetailVO;
import com.nflg.wms.common.pojo.qo.*;
import com.nflg.wms.common.pojo.vo.*;
import com.nflg.wms.repository.service.IQmsIssueTicketService;
import com.nflg.wms.starter.BaseController;
import jakarta.annotation.Resource;
@ -59,11 +51,14 @@ public class QmsIssueTicketController extends BaseController {
}
/**
* PDI发起工单查询任务的不合格检测项
* PDI新建工单并返回不合格检测项
* 1. 创建工单
* 2. 查询任务的不合格检测项
* 3. 返回工单ID和不合格检测项列表
*/
@PostMapping("initiatePdiTicket")
public ApiResult<List<QmsPdiInspectionResultVO>> initiatePdiTicket(@Valid @RequestBody QmsPdiInitiateTicketQO request) {
return ApiResult.success(issueTicketControllerService.initiatePdiTicket(request.getTaskRecordId()));
@PostMapping("createAndQueryPdiTicket")
public ApiResult<QmsPdiCreateTicketResultVO> createAndQueryPdiTicket(@Valid @RequestBody QmsPdiCreateAndQueryTicketQO request) {
return ApiResult.success(issueTicketControllerService.createAndQueryPdiTicket(request));
}
/**

View File

@ -8,6 +8,7 @@ import com.nflg.wms.common.exception.NflgException;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketAddQO;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketAuditQO;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketPdiAddQO;
import com.nflg.wms.common.pojo.qo.QmsPdiCreateAndQueryTicketQO;
import com.nflg.wms.common.pojo.vo.*;
import com.nflg.wms.common.util.UserUtil;
import com.nflg.wms.common.util.VUtil;
@ -84,6 +85,46 @@ public class QmsIssueTicketControllerService {
@Resource
private IDepartmentService departmentService;
/**
* PDI新建工单并返回不合格检测项
* 1. 创建工单
* 2. 查询任务的不合格检测项
* 3. 返回工单ID和不合格检测项列表
*/
@Transactional(rollbackFor = Exception.class)
public QmsPdiCreateTicketResultVO createAndQueryPdiTicket(@Valid QmsPdiCreateAndQueryTicketQO request) {
// 1. 创建工单
addPdiTicket(new QmsIssueTicketPdiAddQO()
.setTaskRecordId(request.getTaskRecordId())
.setIncidentType(request.getIncidentType())
.setHandlers(request.getHandlers().stream()
.map(h -> new QmsIssueTicketPdiAddQO.HandlerItem()
.setTaskResultId(h.getTaskResultId())
.setHandlerUserId(h.getHandlerUserId()))
.collect(Collectors.toList())));
// 2. 查询该任务的不合格检测项
List<QmsPdiInspectionResultVO> unqualifiedItems = initiatePdiTicket(request.getTaskRecordId());
// 3. 查询刚创建的工单
QmsIssueTicket ticket = issueTicketService.lambdaQuery()
.eq(QmsIssueTicket::getSourceType, (short) 1)
.eq(QmsIssueTicket::getSourceId, request.getTaskRecordId())
.orderByDesc(QmsIssueTicket::getCreateTime)
.last("LIMIT 1")
.one();
// 4. 构建返回结果
QmsPdiCreateTicketResultVO result = new QmsPdiCreateTicketResultVO();
if (ticket != null) {
result.setTicketId(ticket.getId());
result.setTicketNo(ticket.getTicketNo());
}
result.setUnqualifiedItems(unqualifiedItems != null ? unqualifiedItems : List.of());
return result;
}
/**
* PDI发起工单查询任务的不合格检测项
*/
@ -260,14 +301,8 @@ public class QmsIssueTicketControllerService {
.one();
if (existingTicket != null) {
// 工单已存在仅新增分配工单处理记录
issueTicketProcessControllerService.addAsync(
existingTicket.getId(),
request.getHandlerUserId(),
request.getInspectionResultIds(),
existingTicket.getTicketNo()
);
return;
// 工单已存在不允许重复创建抛出异常提示使用追加处理记录接口
throw new NflgException(STATE.BusinessError, "该任务已存在工单(工单编号:" + existingTicket.getTicketNo() + "),请使用追加处理记录接口");
}
// 查询检测规则
@ -288,6 +323,29 @@ public class QmsIssueTicketControllerService {
taskRecord.getOrderNo(), "库存检验", rules.getInspectionVersion());
}
// 查询该任务的所有不合格项汇总生成incidentDescription
String incidentDescription = "";
List<QmsPdiInspectionResults> allUnqualifiedResults = pdiInspectionResultsService.lambdaQuery()
.eq(QmsPdiInspectionResults::getTaskId, request.getTaskRecordId())
.eq(QmsPdiInspectionResults::getInspectionItemResults, false)
.list();
if (CollectionUtil.isNotEmpty(allUnqualifiedResults)) {
StringBuilder descBuilder = new StringBuilder();
int index = 1;
for (QmsPdiInspectionResults result : allUnqualifiedResults) {
if (index > 1) {
descBuilder.append("");
}
descBuilder.append(index).append(". ");
descBuilder.append(result.getInspectionContent() != null ? result.getInspectionContent() : "");
descBuilder.append("");
descBuilder.append(result.getInspectionResult() != null ? result.getInspectionResult() : "");
index++;
}
incidentDescription = descBuilder.toString();
}
// 统计不合格检测项数量
long unqualifiedCount = pdiInspectionResultsService.lambdaQuery()
.eq(QmsPdiInspectionResults::getTaskId, request.getTaskRecordId())
@ -304,7 +362,7 @@ public class QmsIssueTicketControllerService {
.setTicketTitle(ticketTitle)
.setProjectNo(taskRecord.getTaskNo())
.setIncidentType(request.getIncidentType())
.setIncidentDescription(request.getIncidentDescription())
.setIncidentDescription(incidentDescription)
.setUnqualifiedQty((int) unqualifiedCount)
.setApprovalStatus((short) 0)
.setStatus((short) 0)
@ -317,14 +375,22 @@ public class QmsIssueTicketControllerService {
issueTicketService.save(entity);
// 异步新增工单处理记录并推送待办
// 按处理人分组异步新增工单处理记录并推送待办
Map<Long, List<Long>> handlerToResultsMap = request.getHandlers().stream()
.collect(Collectors.groupingBy(
QmsIssueTicketPdiAddQO.HandlerItem::getHandlerUserId,
Collectors.mapping(QmsIssueTicketPdiAddQO.HandlerItem::getTaskResultId, Collectors.toList())
));
for (Map.Entry<Long, List<Long>> entry : handlerToResultsMap.entrySet()) {
issueTicketProcessControllerService.addAsync(
entity.getId(),
request.getHandlerUserId(),
request.getInspectionResultIds(),
entry.getKey(),
entry.getValue(),
ticketNo
);
}
}
/**
* 通过来料检测任务ID发起IQC检测任务类型质量问题工单
@ -716,6 +782,15 @@ public class QmsIssueTicketControllerService {
// 查询工单基本信息
QmsIssueTicket ticket = issueTicketService.getById(id);
// 如果工单状态是待流转(0)更新为处理中(1)
if (ticket.getStatus() != null && ticket.getStatus() == 0) {
issueTicketService.lambdaUpdate()
.eq(QmsIssueTicket::getId, id)
.set(QmsIssueTicket::getStatus, (short) 1)
.update();
ticket.setStatus((short) 1); // 更新内存中的状态
}
// 判断是否为工单创建者
boolean isCreator = ticket.getCreateUserId() != null && ticket.getCreateUserId().equals(currentUserId);

View File

@ -65,7 +65,28 @@ public class QmsIssueTicketProcessControllerService {
* 新增工单处理同步 Controller 直接调用
*/
public void add(QmsIssueTicketProcessAddQO request) {
doAdd(request.getIssueTicketId(), request.getHandlerUserId(), request.getTaskResultIds());
// 校验工单是否存在
QmsIssueTicket ticket = issueTicketService.getById(request.getIssueTicketId());
if (ticket == null) {
throw new NflgException(STATE.BusinessError, "工单不存在");
}
// 校验工单状态只有待流转(0)或处理中(1)才能追加处理记录
if (ticket.getStatus() != null && ticket.getStatus() != 0 && ticket.getStatus() != 1) {
throw new NflgException(STATE.BusinessError, "工单状态为已完成,不允许追加处理记录");
}
// 按处理人分组
Map<Long, List<Long>> handlerToResultsMap = request.getHandlers().stream()
.collect(Collectors.groupingBy(
QmsIssueTicketProcessAddQO.HandlerItem::getHandlerUserId,
Collectors.mapping(QmsIssueTicketProcessAddQO.HandlerItem::getTaskResultId, Collectors.toList())
));
// 为每个处理人创建处理记录
for (Map.Entry<Long, List<Long>> entry : handlerToResultsMap.entrySet()) {
doAdd(request.getIssueTicketId(), entry.getKey(), entry.getValue());
}
}
/**

View File

@ -1,6 +1,6 @@
package com.nflg.wms.common.pojo.qo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@ -19,18 +19,6 @@ public class QmsIssueTicketPdiAddQO {
@NotNull(message = "PDI检测任务记录ID不能为空")
private Long taskRecordId;
/**
* 处理人用户ID
*/
@NotNull(message = "处理人用户ID不能为空")
private Long handlerUserId;
/**
* PDI检测结果ID列表qms_pdi_inspection_results.ID存入工单处理的task_result_ids
*/
@NotEmpty(message = "检测结果ID列表不能为空")
private List<Long> inspectionResultIds;
/**
* 事故类型0=一般1=较严重2=严重
*/
@ -38,8 +26,27 @@ public class QmsIssueTicketPdiAddQO {
private Short incidentType;
/**
* 事件描述对不合格项的内容整合
* 处理人列表
*/
@NotBlank(message = "事件描述不能为空")
private String incidentDescription;
@Valid
@NotEmpty(message = "处理人列表不能为空")
private List<HandlerItem> handlers;
/**
* 处理人项
*/
@Data
public static class HandlerItem {
/**
* PDI检测结果IDqms_pdi_inspection_results.ID
*/
@NotNull(message = "检测结果ID不能为空")
private Long taskResultId;
/**
* 处理人用户ID
*/
@NotNull(message = "处理人用户ID不能为空")
private Long handlerUserId;
}
}

View File

@ -1,5 +1,6 @@
package com.nflg.wms.common.pojo.qo;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@ -13,20 +14,33 @@ import java.util.List;
public class QmsIssueTicketProcessAddQO {
/**
* 任务结果ID列表QmsPdiTaskRecord.ID
* 质量问题工单ID
*/
@NotEmpty(message = "任务结果ID列表不能为空")
private List<Long> taskResultIds;
@NotNull(message = "质量问题工单ID不能为空")
private Long issueTicketId;
/**
* 处理人列表
*/
@Valid
@NotEmpty(message = "处理人列表不能为空")
private List<HandlerItem> handlers;
/**
* 处理人项
*/
@Data
public static class HandlerItem {
/**
* 任务结果IDQmsPdiTaskRecord.ID
*/
@NotNull(message = "任务结果ID不能为空")
private Long taskResultId;
/**
* 处理人用户ID
*/
@NotNull(message = "处理人用户ID不能为空")
private Long handlerUserId;
/**
* 质量问题工单ID
*/
@NotNull(message = "质量问题工单ID不能为空")
private Long issueTicketId;
}
}

View File

@ -0,0 +1,52 @@
package com.nflg.wms.common.pojo.qo;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
/**
* PDI新建工单并查询不合格检测项
*/
@Data
public class QmsPdiCreateAndQueryTicketQO {
/**
* PDI检测任务记录IDQmsPdiTaskRecord.ID存入工单的source_id
*/
@NotNull(message = "PDI检测任务记录ID不能为空")
private Long taskRecordId;
/**
* 事故类型0=一般1=较严重2=严重
*/
@NotNull(message = "事故类型不能为空")
private Short incidentType;
/**
* 处理人列表
*/
@Valid
@NotEmpty(message = "处理人列表不能为空")
private List<HandlerItem> handlers;
/**
* 处理人项
*/
@Data
public static class HandlerItem {
/**
* PDI检测结果IDqms_pdi_inspection_results.ID
*/
@NotNull(message = "检测结果ID不能为空")
private Long taskResultId;
/**
* 处理人用户ID
*/
@NotNull(message = "处理人用户ID不能为空")
private Long handlerUserId;
}
}

View File

@ -0,0 +1,27 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import java.util.List;
/**
* PDI新建工单并返回不合格检测项
*/
@Data
public class QmsPdiCreateTicketResultVO {
/**
* 工单ID
*/
private Long ticketId;
/**
* 工单编号
*/
private String ticketNo;
/**
* 不合格检测项列表
*/
private List<QmsPdiInspectionResultVO> unqualifiedItems;
}

View File

@ -111,7 +111,12 @@ public class QmsPdiTaskRecordDefectPageVO {
private Boolean overdue;
/**
* 流程状态有工单时取工单状态0=待流转1=处理中2=已完成无工单时取任务状态2=已完成3=待流转
* 工单ID
*/
private Long ticketId;
/**
* 流程状态有工单时取工单状态0=待流转1=处理中2=已完成无工单时取任务状态3=未发起
*/
private Short status;

View File

@ -92,7 +92,11 @@
t.required_completion_time AS requiredCompletionTime,
t.detection_completion_time AS detectionCompletionTime,
t.overdue,
COALESCE(it.status, t.inspection_enable) AS status,
it.id AS ticketId,
CASE
WHEN it.id IS NOT NULL THEN it.status
ELSE 3
END AS status,
it.ticket_no AS ticketNo,
it.ticket_title AS ticketTitle
FROM qms_pdi_task_record t
@ -132,7 +136,10 @@
AND t.warehouse_no = #{request.warehouseNo}
</if>
<if test="request.status != null">
AND COALESCE(it.status, t.inspection_enable) = #{request.status}
AND CASE
WHEN it.id IS NOT NULL THEN it.status
ELSE 3
END = #{request.status}
</if>
</where>
ORDER BY t.id DESC