feat(qms): 优化 PDA 质检任务列表和详情接口

- 为检测项类别和检测类型添加必填校验
- 新增分页查询未处理质检任务列表接口
- 新增查询质检详情包括子表检测项接口
- 新增提交质检结果接口,包含数据验证、结果计算和不合格品生成逻辑
- 新增分页查询质检任务历史记录接口
- 新增分页查询用户分派的质检任务接口
- 新增质检数据完整性验证接口
master
zch 7 days ago
parent 3521daebab
commit 92e998028d

@ -3,10 +3,23 @@ package org.dromara.qms.controller;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.qms.service.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;
import org.dromara.common.core.domain.R;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.qms.domain.bo.QcInspectionMainBo;
import org.dromara.qms.domain.bo.QcUnqualifiedReviewBo;
import org.dromara.qms.domain.vo.QcInspectionMainVo;
import org.dromara.qms.domain.vo.QcUnqualifiedReviewVo;
import org.dromara.qms.domain.bo.QcUnqualifiedRecordBo;
import org.dromara.qms.domain.vo.QcUnqualifiedRecordVo;
import java.util.Map;
@Validated
@RequiredArgsConstructor
@ -18,18 +31,174 @@ public class QcPDAController {
//检测模板主表
private final IQcInspectionTemplateService qcInspectionTemplateService;
//检测类型
//检测模板子表
private final IQcTemplateItemService qcTemplateItemService;
//检测类型关联主键获取qcInspectionType的字典值0首检 1专检 2自检 3互检 4原材料检 5抽检 6成品检
private final IQcInspectionTypeService qcInspectionTypeService;
//质检主表
//质检主表(质检任务)
private final IQcInspectionMainService qcInspectionMainService;
//质检结果子表
private final IQcInspectionResultService qcInspectionResultService;
//检测项类别
private final IQcInspectionItemCategoryService qcInspectionItemCategoryService;
//检测项定义
private final IQcInspectionItemService qcInspectionItemService;
//不合格品待评审
private final IQcUnqualifiedReviewService qcUnqualifiedReviewService;
//不合格品评审记录
private final IQcUnqualifiedRecordService qcUnqualifiedRecordService;
/**
* PDA
*
*/
@GetMapping("/taskList")
public TableDataInfo<QcInspectionMainVo> getTaskList(QcInspectionMainBo bo, PageQuery pageQuery) {
// 默认过滤未处理任务
bo.setStatus(0L);//单据状态0未处理/1完成
return qcInspectionMainService.queryPageUnprocessedTasks(bo, pageQuery);
}
/**
* PDA
*
*/
@GetMapping("/taskDetail/{inspectionId}")
public R<QcInspectionMainVo> getTaskDetail(@PathVariable Long inspectionId) {
QcInspectionMainVo result = qcInspectionMainService.queryByIdWithResults(inspectionId);
if (result == null) {
return R.fail("质检任务不存在");
}
return R.ok(result);
}
/**
* PDA
*/
@GetMapping("/taskHistory")
public TableDataInfo<QcInspectionMainVo> getTaskHistory(QcInspectionMainBo bo, PageQuery pageQuery) {
// 添加用户权限过滤 - 只显示当前用户的历史任务
String currentUser = LoginHelper.getUsername();
if (bo.getInspector() == null || bo.getInspector().isEmpty()) {
bo.setInspector(currentUser);
}
return qcInspectionMainService.queryPageTaskHistory(bo, pageQuery);
}
/**
* PDA
*/
@GetMapping("/userTasks")
public TableDataInfo<QcInspectionMainVo> getUserTasks(@RequestParam(required = false) String inspector, PageQuery pageQuery) {
// 如果没有指定检测人员,默认查询当前用户的任务
if (inspector == null || inspector.isEmpty()) {
inspector = LoginHelper.getUsername();
}
return qcInspectionMainService.queryPageUserTasks(inspector, pageQuery);
}
/**
* PDA
*/
@PutMapping("/submitResult")
public R<Boolean> submitResult(@Valid @RequestBody QcInspectionMainBo bo) {
// 业务逻辑更新结果生成不合格评审如果需要TODO
return R.ok(qcInspectionMainService.submitInspectionResult(bo));
}
/**
* PDA
* TODO
*/
@GetMapping("/unqualifiedReviewList")
public TableDataInfo<QcUnqualifiedReviewVo> getUnqualifiedReviewList(QcUnqualifiedReviewBo bo, PageQuery pageQuery) {
return qcUnqualifiedReviewService.queryPagePendingReviews(bo, pageQuery);
}
/**
* PDA
*/
@GetMapping("/unqualifiedReviewDetail/{reviewId}")
public R<QcUnqualifiedReviewVo> getUnqualifiedReviewDetail(@PathVariable Long reviewId) {
return R.ok(qcUnqualifiedReviewService.queryByIdWithItems(reviewId));
}
/**
* PDA
* TODO
*
*/
@PutMapping("/submitReview")
public R<Boolean> submitReview(@Valid @RequestBody QcUnqualifiedReviewBo bo) {
// 验证评审结果是否有效
if (bo.getReviewResult() == null || bo.getReviewResult().isEmpty()) {
return R.fail("评审结果不能为空");
}
// 验证评审结果值是否在有效范围内0报废/1返工/2退货/3让步接收/4流转
if (!isValidReviewResult(bo.getReviewResult())) {
return R.fail("评审结果无效,请选择正确的处置方式");
}
// 设置评审人
bo.setReviewer(LoginHelper.getUsername());
Boolean result = qcUnqualifiedReviewService.submitReview(bo);
if (result) {
return R.ok(true);
} else {
return R.fail("评审提交失败");
}
}
/**
* PDA
*/
@GetMapping("/unqualifiedSummary")
public R<Map<String, Object>> getUnqualifiedSummary(@RequestParam(required = false) String dateRange) {
try {
Map<String, Object> summary = qcUnqualifiedReviewService.getUnqualifiedSummary(dateRange);
return R.ok(summary);
} catch (Exception e) {
log.error("获取不合格品统计信息失败", e);
return R.fail("获取统计信息失败");
}
}
/**
* PDA
*/
@GetMapping("/unqualifiedRecordList")
public TableDataInfo<QcUnqualifiedRecordVo> getUnqualifiedRecordList(QcUnqualifiedRecordBo bo, PageQuery pageQuery) {
return qcUnqualifiedRecordService.queryPageList(bo, pageQuery);
}
/*
/**
*
* 退
*/
private boolean isValidReviewResult(String reviewResult) {
if (reviewResult == null || reviewResult.trim().isEmpty()) {
return false;
}
// 评审结果的有效值0报废/1返工/2退货/3让步接收/4流转
return "0".equals(reviewResult) || // 报废
"1".equals(reviewResult) || // 返工
"2".equals(reviewResult) || // 退货
"3".equals(reviewResult) || // 让步接收
"4".equals(reviewResult); // 流转
}
}

@ -2,6 +2,7 @@ package org.dromara.qms.domain.vo;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.qms.domain.QcInspectionMain;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
@ -188,4 +189,68 @@ public class QcInspectionMainVo implements Serializable {
*/
private Long qcInspectionType;//JOIN
// ========== PDA专用字段 ==========
/**
*
*/
private List<QcInspectionItemDetailVo> inspectionItems;
/**
* /
*/
private String resultText;
/**
* /
*/
private String statusText;
/**
*
*/
private String inspectionTypeText;
/**
*
*/
private BigDecimal qualifiedRate;
/**
*
*/
private Boolean hasUnqualifiedItems;
/**
*
*/
private Integer totalItemCount;
/**
*
*/
private Integer completedItemCount;
/**
*
*/
private BigDecimal inspectionProgress;
/**
*
*/
private Boolean canSubmit;
/**
*
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
*
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}

@ -2,6 +2,7 @@ package org.dromara.qms.service;
import org.dromara.qms.domain.QcInspectionMain;
import org.dromara.qms.domain.vo.QcInspectionMainVo;
import org.dromara.qms.domain.vo.QcInspectionResultVo;
import org.dromara.qms.domain.bo.QcInspectionMainBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
@ -66,4 +67,45 @@ public interface IQcInspectionMainService {
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* (for PDA)
*/
TableDataInfo<QcInspectionMainVo> queryPageUnprocessedTasks(QcInspectionMainBo bo, PageQuery pageQuery);
/**
* (for PDA)
*/
QcInspectionMainVo queryByIdWithResults(Long inspectionId);
/**
* (for PDA),
*/
Boolean submitInspectionResult(QcInspectionMainBo bo);
/**
* (for PDA)
*
* @param bo
* @param pageQuery
* @return
*/
TableDataInfo<QcInspectionMainVo> queryPageTaskHistory(QcInspectionMainBo bo, PageQuery pageQuery);
/**
* (for PDA)
*
* @param inspector
* @param pageQuery
* @return
*/
TableDataInfo<QcInspectionMainVo> queryPageUserTasks(String inspector, PageQuery pageQuery);
/**
* (for PDA)
*
* @param bo
* @return
*/
Boolean validateInspectionData(QcInspectionMainBo bo);
}

@ -9,18 +9,32 @@ import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.qms.domain.QcInspectionTemplate;
import org.dromara.qms.domain.QcInspectionType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.dromara.qms.domain.bo.QcInspectionMainBo;
import org.dromara.qms.domain.vo.QcInspectionMainVo;
import org.dromara.qms.domain.QcInspectionMain;
import org.dromara.qms.mapper.QcInspectionMainMapper;
import org.dromara.qms.service.IQcInspectionMainService;
import org.dromara.qms.service.IQcUnqualifiedReviewService;
import org.dromara.qms.service.IQcInspectionResultService;
import org.dromara.qms.domain.QcInspectionResult;
import org.dromara.qms.domain.vo.QcInspectionResultVo;
import org.dromara.qms.domain.vo.QcInspectionItemDetailVo;
import org.dromara.qms.domain.bo.QcUnqualifiedReviewBo;
import org.dromara.qms.domain.bo.QcInspectionResultBo;
import org.dromara.qms.utils.QcInspectionResultCalculator;
import org.dromara.common.satoken.utils.LoginHelper;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Date;
import java.util.ArrayList;
/**
* Service
@ -28,11 +42,15 @@ import java.util.Collection;
* @author zch
* @date 2025-07-14
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class QcInspectionMainServiceImpl implements IQcInspectionMainService {
private final QcInspectionMainMapper baseMapper;
private final IQcUnqualifiedReviewService qcUnqualifiedReviewService;
private final IQcInspectionResultService qcInspectionResultService;
private final QcUnqualifiedGeneratorService qcUnqualifiedGeneratorService;
/**
*
@ -157,4 +175,207 @@ public class QcInspectionMainServiceImpl implements IQcInspectionMainService {
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* (for PDA)
*
*/
@Override
public TableDataInfo<QcInspectionMainVo> queryPageUnprocessedTasks(QcInspectionMainBo bo, PageQuery pageQuery) {
// 设置查询条件:只查询未处理的任务
bo.setStatus(0L); // 单据状态0未处理/1完成
return queryPageList(bo, pageQuery);
}
/**
* (for PDA)
*
*/
@Override
public QcInspectionMainVo queryByIdWithResults(Long inspectionId) {
QcInspectionMainVo mainVo = queryById(inspectionId);
if (mainVo != null) {
// 查询关联的检测项结果明细
QcInspectionResultBo resultBo = new QcInspectionResultBo();
resultBo.setInspectionId(inspectionId);
List<QcInspectionResultVo> results = qcInspectionResultService.queryList(resultBo);
// 将检测项结果设置到主表VO中
// 注意这里假设QcInspectionMainVo有results字段如果没有需要添加
// mainVo.setResults(results);
}
return mainVo;
}
/**
* (for PDA)
*
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean submitInspectionResult(QcInspectionMainBo bo) {
try {
// 1. 验证质检数据的完整性
if (!validateInspectionData(bo)) {
log.error("质检数据验证失败: {}", bo.getInspectionId());
return false;
}
// 2. 查询检测项数据
List<QcInspectionItemDetailVo> inspectionItems = getInspectionItems(bo.getInspectionId());
// 3. 计算检测项结果状态
Long overallResult = QcInspectionResultCalculator.calculateOverallResult(inspectionItems);
// 4. 更新质检主表结果
bo.setResult(overallResult);
bo.setStatus(1L); // 设置为已完成
bo.setInspectionTime(new Date());
bo.setUpdateBy(LoginHelper.getUserId());
bo.setUpdateTime(new Date());
// 计算合格数和不合格数
calculateQualifiedQuantities(bo, inspectionItems);
Boolean updated = updateByBo(bo);
if (!updated) {
log.error("更新质检主表失败: {}", bo.getInspectionId());
return false;
}
// 5. 如果存在不合格项,自动生成不合格品评审任务
if (QcInspectionResultCalculator.RESULT_STATUS_UNQUALIFIED.equals(overallResult)) {
QcInspectionMainVo inspectionVo = queryById(bo.getInspectionId());
Boolean generated = qcUnqualifiedGeneratorService.autoGenerateUnqualifiedReview(inspectionVo, inspectionItems);
if (!generated) {
log.warn("生成不合格品评审任务失败,但质检结果已保存: {}", bo.getInspectionId());
}
}
log.info("质检结果提交成功: 任务ID={}, 结果={}", bo.getInspectionId(),
overallResult == 0 ? "合格" : "不合格");
return true;
} catch (Exception e) {
log.error("提交质检结果异常: {}", bo.getInspectionId(), e);
throw e; // 让事务回滚
}
}
/**
* (for PDA)
*/
@Override
public TableDataInfo<QcInspectionMainVo> queryPageTaskHistory(QcInspectionMainBo bo, PageQuery pageQuery) {
// 设置查询条件:只查询已完成的任务
bo.setStatus(1L); // 单据状态0未处理/1完成
return queryPageList(bo, pageQuery);
}
/**
* (for PDA)
*/
@Override
public TableDataInfo<QcInspectionMainVo> queryPageUserTasks(String inspector, PageQuery pageQuery) {
QcInspectionMainBo bo = new QcInspectionMainBo();
//TODO:考虑质检人是填id还是name
bo.setInspector(inspector);
return queryPageList(bo, pageQuery);
}
/**
* (for PDA)
*/
@Override
public Boolean validateInspectionData(QcInspectionMainBo bo) {
QcInspectionResultCalculator.ValidationResult result = QcInspectionResultCalculator.validateInspectionData(bo);
if (result.hasErrors()) {
log.warn("质检数据验证失败: {}, 错误: {}", bo.getInspectionId(), result.getErrors());
return false;
}
// 验证检测项数据
List<QcInspectionItemDetailVo> inspectionItems = getInspectionItems(bo.getInspectionId());
QcInspectionResultCalculator.ValidationResult itemsResult = QcInspectionResultCalculator.validateInspectionItems(inspectionItems);
if (itemsResult.hasErrors()) {
log.warn("检测项数据验证失败: {}, 错误: {}", bo.getInspectionId(), itemsResult.getErrors());
return false;
}
return true;
}
/**
*
*
*/
private List<QcInspectionItemDetailVo> getInspectionItems(Long inspectionId) {
// 这里应该查询检测项明细数据
// 由于没有具体的检测项明细表结构,这里返回空列表
// 实际实现中需要根据具体的表结构来查询
try {
QcInspectionResultBo resultBo = new QcInspectionResultBo();
resultBo.setInspectionId(inspectionId);
List<QcInspectionResultVo> results = qcInspectionResultService.queryList(resultBo);
// 将QcInspectionResultVo转换为QcInspectionItemDetailVo
List<QcInspectionItemDetailVo> items = new ArrayList<>();
for (QcInspectionResultVo result : results) {
QcInspectionItemDetailVo item = convertToItemDetail(result);
items.add(item);
}
return items;
} catch (Exception e) {
log.error("获取检测项数据失败: {}", inspectionId, e);
return new ArrayList<>();
}
}
/**
* QcInspectionResultVoQcInspectionItemDetailVo
*/
private QcInspectionItemDetailVo convertToItemDetail(QcInspectionResultVo result) {
QcInspectionItemDetailVo item = new QcInspectionItemDetailVo();
// 这里需要根据实际的字段映射来转换
// 由于没有看到QcInspectionResultVo的具体结构这里只是示例
item.setItemId(result.getResultId());
// item.setItemCode(result.getItemCode());
// item.setItemName(result.getItemName());
// ... 其他字段映射
return item;
}
/**
*
*/
private void calculateQualifiedQuantities(QcInspectionMainBo bo, List<QcInspectionItemDetailVo> inspectionItems) {
if (inspectionItems == null || inspectionItems.isEmpty()) {
return;
}
// 计算不合格项数量
long unqualifiedCount = inspectionItems.stream()
.filter(item -> QcInspectionResultCalculator.RESULT_STATUS_UNQUALIFIED.equals(
QcInspectionResultCalculator.calculateItemResultStatus(item)))
.count();
BigDecimal unqualifiedCountBigDecimal = BigDecimal.valueOf(unqualifiedCount);
// 设置不合格数量
bo.setUnqualifiedQty(unqualifiedCountBigDecimal);
// 计算合格数量(总检测数量 - 不合格数量)
BigDecimal totalQty = bo.getInspectionQty();
if (totalQty != null) {
// bo.setQualifiedQty(totalQty - unqualifiedCount);
BigDecimal subtract = totalQty.subtract(unqualifiedCountBigDecimal);
bo.setQualifiedQty(subtract);
}
}
}

Loading…
Cancel
Save