Compare commits

...

2 Commits

Author SHA1 Message Date
funny 9542751147 Merge branch 'qms/yf' into qms/develop 2026-04-29 16:39:54 +08:00
funny 0da38080ca feat(qms): 完善工单处理流程及领导审批功能
- 异步新增工单处理时推送待办消息,整合新增及推送操作
- 新增领导暂存与提交接口及对应服务方法,支持领导审批逻辑
- 提交工单处理时校验审批状态,支持根据审批结果推送待办
- 领导提交工单处理时校验审批结果,支持驳回和同意两种流程
- 同意领导审批时,自动检测工单所有处理记录完成状态,更新工单状态
- 领导暂存时保存审批意见和审批结果,写入领导用户信息
- 检测任务完成时增加是否延期状态标记
- 删除冗余同步推送待办代码,优化代码结构
2026-04-29 16:38:43 +08:00
6 changed files with 217 additions and 23 deletions

View File

@ -5,6 +5,7 @@ import com.nflg.qms.admin.service.QmsIssueTicketProcessMeasureControllerService;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketProcessAddQO;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketProcessDraftQO;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketProcessLeaderDraftQO;
import com.nflg.wms.starter.BaseController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
@ -52,4 +53,22 @@ public class QmsIssueTicketProcessController extends BaseController {
issueTicketProcessControllerService.submit(request);
return ApiResult.success();
}
/**
* 领导暂存工单处理
*/
@PostMapping("leaderDraft")
public ApiResult<Void> leaderDraft(@Valid @RequestBody QmsIssueTicketProcessLeaderDraftQO request) {
issueTicketProcessMeasureControllerService.leaderDraft(request);
return ApiResult.success();
}
/**
* 领导提交工单处理
*/
@PostMapping("leaderSubmit")
public ApiResult<Void> leaderSubmit(@Valid @RequestBody QmsIssueTicketProcessLeaderDraftQO request) {
issueTicketProcessControllerService.leaderSubmit(request);
return ApiResult.success();
}
}

View File

@ -208,26 +208,13 @@ public class QmsIssueTicketControllerService {
issueTicketService.save(entity);
// 异步新增工单处理记录
// 异步新增工单处理记录并推送待办
issueTicketProcessControllerService.addAsync(
entity.getId(),
request.getHandlerUserId(),
request.getInspectionResultIds()
request.getInspectionResultIds(),
ticketNo
);
// 推送待办消息
Long sourceTypeId = dictionaryItemService.getIdByCode("MessageType", "PDIDefectiveProductHandling");
VUtil.trueThrowBusinessError(Objects.isNull(sourceTypeId)).throwMessage("消息类型不存在");
User handlerUser = userService.getById(request.getHandlerUserId());
QmsTodoItem todoItem = new QmsTodoItem()
.setCode(ticketNo)
.setIsRead(false)
.setSourceTypeId(sourceTypeId)
.setSourceId(entity.getId())
.setCreateUserId(request.getHandlerUserId())
.setCreateUserName(handlerUser != null ? handlerUser.getUserName() : userName)
.setCreateTime(now);
todoItemService.save(todoItem);
}
/**

View File

@ -4,9 +4,16 @@ import com.nflg.wms.common.constant.STATE;
import com.nflg.wms.common.exception.NflgException;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketProcessAddQO;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketProcessDraftQO;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketProcessLeaderDraftQO;
import com.nflg.wms.common.util.VUtil;
import com.nflg.wms.repository.entity.QmsIssueTicket;
import com.nflg.wms.repository.entity.QmsIssueTicketProcess;
import com.nflg.wms.repository.entity.QmsTodoItem;
import com.nflg.wms.repository.entity.User;
import com.nflg.wms.repository.service.IDictionaryItemService;
import com.nflg.wms.repository.service.IQmsIssueTicketProcessService;
import com.nflg.wms.repository.service.IQmsIssueTicketService;
import com.nflg.wms.repository.service.IQmsTodoItemService;
import com.nflg.wms.repository.service.IUserService;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
@ -14,7 +21,9 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
@ -32,6 +41,15 @@ public class QmsIssueTicketProcessControllerService {
@Resource
private QmsIssueTicketProcessMeasureControllerService issueTicketProcessMeasureControllerService;
@Resource
private IQmsIssueTicketService issueTicketService;
@Resource
private IQmsTodoItemService todoItemService;
@Resource
private IDictionaryItemService dictionaryItemService;
/**
* 新增工单处理同步 Controller 直接调用
*/
@ -40,14 +58,27 @@ public class QmsIssueTicketProcessControllerService {
}
/**
* 异步新增工单处理供内部服务调用
* 异步新增工单处理并推送待办供内部服务调用
*/
@Async("ticketTaskExecutor")
public void addAsync(Long issueTicketId, Long handlerUserId, List<Long> taskResultIds) {
doAdd(issueTicketId, handlerUserId, taskResultIds);
public void addAsync(Long issueTicketId, Long handlerUserId, List<Long> taskResultIds, String ticketNo) {
Long processId = doAdd(issueTicketId, handlerUserId, taskResultIds);
// 推送待办消息
Long sourceTypeId = dictionaryItemService.getIdByCode("MessageType", "PDIDefectiveProductHandling");
User handlerUser = userService.getById(handlerUserId);
QmsTodoItem todoItem = new QmsTodoItem()
.setCode(ticketNo)
.setIsRead(false)
.setSourceTypeId(sourceTypeId)
.setSourceId(processId)
.setCreateUserId(handlerUserId)
.setCreateUserName(handlerUser != null ? handlerUser.getUserName() : null)
.setCreateTime(LocalDateTime.now());
todoItemService.save(todoItem);
}
private void doAdd(Long issueTicketId, Long handlerUserId, List<Long> taskResultIds) {
private Long doAdd(Long issueTicketId, Long handlerUserId, List<Long> taskResultIds) {
User user = userService.getById(handlerUserId);
if (user == null) {
throw new NflgException(STATE.BusinessError, "处理人用户不存在");
@ -62,14 +93,120 @@ public class QmsIssueTicketProcessControllerService {
.collect(Collectors.joining(",")));
issueTicketProcessService.save(entity);
return entity.getId();
}
/**
* 提交工单处理更新工单处理记录有措施内容则新增一条措施记录
* TODO: 后续补充推送到下一级的逻辑
* 提交工单处理
* 1. 校验 approvalStatus 必传
* 2. 执行保存逻辑复用 draft
* 3. approvalStatus=1驳回推送待办给工单创建人
* 4. approvalStatus=0通过推送给当前用户所在部门负责人TODO: 部门负责人字段暂无后续补充
*/
@Transactional(rollbackFor = Exception.class)
public void submit(@Valid QmsIssueTicketProcessDraftQO request) {
// 1. 校验审批状态必传
VUtil.trueThrowBusinessError(Objects.isNull(request.getApprovalStatus()))
.throwMessage("提交时审批状态不能为空");
// 2. 保存数据
issueTicketProcessMeasureControllerService.draft(request);
// 3. 查询工单处理记录获取关联的工单
QmsIssueTicketProcess process = issueTicketProcessService.getById(request.getId());
QmsIssueTicket ticket = issueTicketService.getById(process.getIssueTicketId());
VUtil.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("关联的质量问题工单不存在");
Long sourceTypeId = dictionaryItemService.getIdByCode("MessageType", "RejectedPDIDefectiveProductHandling");
LocalDateTime now = LocalDateTime.now();
if (request.getApprovalStatus() == 1) {
// 驳回推送待办给工单创建人分配任务的user
User creator = userService.getById(ticket.getCreateUserId());
QmsTodoItem todoItem = new QmsTodoItem()
.setCode(ticket.getTicketNo())
.setIsRead(false)
.setSourceTypeId(sourceTypeId)
.setSourceId(process.getId())
.setCreateUserId(ticket.getCreateUserId())
.setCreateUserName(creator != null ? creator.getUserName() : null)
.setCreateTime(now);
todoItemService.save(todoItem);
} else if (request.getApprovalStatus() == 0) {
// 通过推送给当前用户所在部门负责人
// TODO: Department 表暂无负责人字段后续补充
}
}
/**
* 领导提交工单处理
* 1. 校验 leaderApprovalResult 必传
* 2. 执行保存逻辑复用 leaderDraft+ 写入审批时间
* 3. leaderApprovalResult=0驳回推送待办给处理人
* 4. leaderApprovalResult=1同意结束流程
*/
@Transactional(rollbackFor = Exception.class)
public void leaderSubmit(@Valid QmsIssueTicketProcessLeaderDraftQO request) {
// 1. 校验领导审批结果必传
VUtil.trueThrowBusinessError(Objects.isNull(request.getLeaderApprovalResult()))
.throwMessage("提交时领导审批结果不能为空");
// 2. 保存数据
issueTicketProcessMeasureControllerService.leaderDraft(request);
// 3. 写入领导审批时间
LocalDateTime now = LocalDateTime.now();
issueTicketProcessService.lambdaUpdate()
.eq(QmsIssueTicketProcess::getId, request.getId())
.set(QmsIssueTicketProcess::getLeaderApprovalTime, now)
.update();
if (request.getLeaderApprovalResult() == 0) {
// 驳回推送待办给处理人
QmsIssueTicketProcess process = issueTicketProcessService.getById(request.getId());
QmsIssueTicket ticket = issueTicketService.getById(process.getIssueTicketId());
VUtil.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("关联的质量问题工单不存在");
Long sourceTypeId = dictionaryItemService.getIdByCode("MessageType", "RejectedPDIDefectiveProductHandling");
User handler = userService.getById(process.getHandlerUserId());
QmsTodoItem todoItem = new QmsTodoItem()
.setCode(ticket.getTicketNo())
.setIsRead(false)
.setSourceTypeId(sourceTypeId)
.setSourceId(process.getId())
.setCreateUserId(process.getHandlerUserId())
.setCreateUserName(handler != null ? handler.getUserName() : null)
.setCreateTime(now);
todoItemService.save(todoItem);
} else if (request.getLeaderApprovalResult() == 1) {
// 同意检查同一工单下所有处理记录是否都已完成
QmsIssueTicketProcess current = issueTicketProcessService.getById(request.getId());
Long issueTicketId = current.getIssueTicketId();
// 查询同一工单下是否存在未完成的记录
// 完成条件leaderApprovalResult=1 leaderApprovalResult为空 approvalStatus=1
// 未完成不满足以上任一条件的记录
long notCompleted = issueTicketProcessService.lambdaQuery()
.eq(QmsIssueTicketProcess::getIssueTicketId, issueTicketId)
.and(w -> w
// 排除 leaderApprovalResult=1 已完成
.ne(true, QmsIssueTicketProcess::getLeaderApprovalResult, (short) 1)
.or()
.isNull(QmsIssueTicketProcess::getLeaderApprovalResult))
// leaderApprovalResult 不为1的记录中排除 approvalStatus=1 处理人驳回也算完成
.and(w -> w
.ne(true, QmsIssueTicketProcess::getApprovalStatus, (short) 1)
.or()
.isNull(QmsIssueTicketProcess::getApprovalStatus))
.count();
if (notCompleted == 0) {
// 所有处理记录都已完成更新工单状态为已完成(2)
issueTicketService.lambdaUpdate()
.eq(QmsIssueTicket::getId, issueTicketId)
.set(QmsIssueTicket::getStatus, (short) 2)
.update();
}
}
}
}

View File

@ -2,6 +2,8 @@ package com.nflg.qms.admin.service;
import cn.hutool.core.util.StrUtil;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketProcessDraftQO;
import com.nflg.wms.common.pojo.qo.QmsIssueTicketProcessLeaderDraftQO;
import com.nflg.wms.common.util.UserUtil;
import com.nflg.wms.common.util.VUtil;
import com.nflg.wms.repository.entity.QmsIssueTicketProcess;
import com.nflg.wms.repository.entity.QmsIssueTicketProcessMeasure;
@ -51,4 +53,23 @@ public class QmsIssueTicketProcessMeasureControllerService {
issueTicketProcessMeasureService.save(measure);
}
}
/**
* 领导暂存更新领导审批意见审批结果写入领导信息
*/
@Transactional(rollbackFor = Exception.class)
public void leaderDraft(@Valid QmsIssueTicketProcessLeaderDraftQO request) {
QmsIssueTicketProcess process = issueTicketProcessService.getById(request.getId());
VUtil.trueThrowBusinessError(Objects.isNull(process)).throwMessage("工单处理记录不存在");
issueTicketProcessService.lambdaUpdate()
.eq(QmsIssueTicketProcess::getId, request.getId())
.set(request.getLeaderApprovalOpinion() != null,
QmsIssueTicketProcess::getLeaderApprovalOpinion, request.getLeaderApprovalOpinion())
.set(request.getLeaderApprovalResult() != null,
QmsIssueTicketProcess::getLeaderApprovalResult, request.getLeaderApprovalResult())
.set(QmsIssueTicketProcess::getLeaderUserId, UserUtil.getUserId())
.set(QmsIssueTicketProcess::getLeaderUserName, UserUtil.getUserName())
.update();
}
}

View File

@ -192,10 +192,13 @@ public class QmsPdiInspectionResultsControllerService {
request.getOverallResult() != null && request.getOverallResult())
.update();
// 5. 设置检测完成时间状态改为已完成
// 5. 设置检测完成时间是否延期状态改为已完成
boolean overdue = taskRecord.getRequiredCompletionTime() != null
&& now.isAfter(taskRecord.getRequiredCompletionTime());
taskRecordService.lambdaUpdate()
.eq(QmsPdiTaskRecord::getId, taskRecord.getId())
.set(QmsPdiTaskRecord::getDetectionCompletionTime, now)
.set(QmsPdiTaskRecord::getOverdue, overdue)
.set(QmsPdiTaskRecord::getInspectionEnable, 2)
.update();

View File

@ -0,0 +1,27 @@
package com.nflg.wms.common.pojo.qo;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* 质量问题工单处理 领导暂存/提交参数
*/
@Data
public class QmsIssueTicketProcessLeaderDraftQO {
/**
* 工单处理IDQmsIssueTicketProcess.ID
*/
@NotNull(message = "工单处理ID不能为空")
private Long id;
/**
* 领导审批意见可选
*/
private String leaderApprovalOpinion;
/**
* 领导审批结果可选0=驳回1=同意
*/
private Short leaderApprovalResult;
}