diff --git a/zt-module-qms/zt-module-qms-api/src/main/java/com/zt/plat/module/qms/enums/QmsCommonConstant.java b/zt-module-qms/zt-module-qms-api/src/main/java/com/zt/plat/module/qms/enums/QmsCommonConstant.java index 87666064..85387df7 100644 --- a/zt-module-qms/zt-module-qms-api/src/main/java/com/zt/plat/module/qms/enums/QmsCommonConstant.java +++ b/zt-module-qms/zt-module-qms-api/src/main/java/com/zt/plat/module/qms/enums/QmsCommonConstant.java @@ -158,6 +158,9 @@ public interface QmsCommonConstant { /** 平行 **/ String ASSAY_TYPE_SINGLE_PARALLEL = "single_parallel"; + /** 双杯平行 **/ + String ASSAY_TYPE_DOUBLE_PARALLEL = "double_parallel"; + /** 配料 **/ String ASSAY_PROJECT_USAGE_INGREDIENT = "ingredient"; diff --git a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/controller/admin/SampleEntrustController.java b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/controller/admin/SampleEntrustController.java index 78919bde..6cd06cd0 100644 --- a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/controller/admin/SampleEntrustController.java +++ b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/controller/admin/SampleEntrustController.java @@ -14,14 +14,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import com.alibaba.fastjson2.JSONObject; import com.yomahub.liteflow.core.FlowExecutor; import com.yomahub.liteflow.flow.LiteflowResponse; import com.zt.plat.framework.business.interceptor.BusinessControllerMarker; import com.zt.plat.framework.common.pojo.CommonResult; import com.zt.plat.framework.common.pojo.vo.BatchDeleteReqVO; import com.zt.plat.framework.datapermission.core.annotation.DeptDataPermissionIgnore; -import com.zt.plat.module.qms.business.bus.controller.vo.*; import com.zt.plat.module.qms.business.bus.liteflow.param.SampleEntrustParam; import com.zt.plat.module.qms.business.bus.liteflow.slot.SampleEntrustContext; import com.zt.plat.module.qms.business.bus.service.SampleEntrustService; diff --git a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/param/SampleTaskAssignManualTypeParam.java b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/param/SampleTaskAssignManualTypeParam.java index 0f280ba9..65c634b2 100644 --- a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/param/SampleTaskAssignManualTypeParam.java +++ b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/param/SampleTaskAssignManualTypeParam.java @@ -13,7 +13,7 @@ import lombok.experimental.Accessors; public class SampleTaskAssignManualTypeParam { /** 分析人员 **/ - private AssignAssayUser assignAssayUser; + private List assignAssayUserList; /** 检测任务id列表 **/ private List assayTaskDataIdList; diff --git a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/sample/taskassign/SampleTaskAssignContextInitCmp.java b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/sample/taskassign/SampleTaskAssignContextInitCmp.java index 6acdbd48..fafccbfd 100644 --- a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/sample/taskassign/SampleTaskAssignContextInitCmp.java +++ b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/sample/taskassign/SampleTaskAssignContextInitCmp.java @@ -57,7 +57,7 @@ public class SampleTaskAssignContextInitCmp extends NodeComponent { if (this.getRequestData() instanceof SampleTaskAssignManualTypeParam) { SampleTaskAssignManualTypeParam sampleTaskAssignManualParam = this.getRequestData(); sampleTaskAssignContext.setSampleTaskAssignType(SampleTaskAssignTypeEnum.MANUAL_TYPE); - sampleTaskAssignContext.setAssignAssayUser(sampleTaskAssignManualParam.getAssignAssayUser()); + sampleTaskAssignContext.setAssignAssayUserList(sampleTaskAssignManualParam.getAssignAssayUserList()); sampleTaskAssignContext.setAssayTaskDataIdList(sampleTaskAssignManualParam.getAssayTaskDataIdList()); } diff --git a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/sample/taskassign/SampleTaskAssignManualTypeCmp.java b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/sample/taskassign/SampleTaskAssignManualTypeCmp.java index cf66727c..dc31836f 100644 --- a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/sample/taskassign/SampleTaskAssignManualTypeCmp.java +++ b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/liteflow/sample/taskassign/SampleTaskAssignManualTypeCmp.java @@ -2,6 +2,7 @@ package com.zt.plat.module.qms.business.bus.liteflow.sample.taskassign; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -62,7 +63,9 @@ public class SampleTaskAssignManualTypeCmp extends NodeComponent { String loginRealname = sampleTaskAssignContext.getLoginRealname(); LoginUser loginUser = sampleTaskAssignContext.getLoginUser(); LocalDateTime currentDateTime = sampleTaskAssignContext.getCurrentDateTime(); - AssignAssayUser assignAssayUser = sampleTaskAssignContext.getAssignAssayUser(); +// AssignAssayUser assignAssayUser = sampleTaskAssignContext.getAssignAssayUser(); + List assignAssayUserList = sampleTaskAssignContext.getAssignAssayUserList(); + int assignAssayUserCount = assignAssayUserList.size(); List assayTaskDataIdList = sampleTaskAssignContext.getAssayTaskDataIdList(); List businessAssayTaskDataList = businessAssayTaskDataMapper.selectByIds(assayTaskDataIdList); List businessSubSampleIdList = businessAssayTaskDataList.stream().map(m -> m.getBusinessSubSampleId()).distinct().collect(Collectors.toList()); @@ -81,22 +84,121 @@ public class SampleTaskAssignManualTypeCmp extends NodeComponent { //任务分配单明细 List businessAssayTaskDetailList = new ArrayList<>(); + // 用于缓存已处理的任务单,避免同一用户在同一业务类型下重复查询数据库 + // Key: userId + dictionaryBusinessId, Value: BusinessAssayTaskDO + Map existingTaskCache = new HashMap<>(); //按方法类型分组 Map> groupConfigAssayMethodListMap = configAssayMethodList.stream().collect(Collectors.groupingBy(ConfigAssayMethodDO::getDictionaryBusinessId)); //Map> groupBusinessAssayTaskDataListMap = businessAssayTaskDataList.stream().collect(Collectors.groupingBy(BusinessAssayTaskDataDO::get)); for (Map.Entry> entry : groupConfigAssayMethodListMap.entrySet()) { - long key = entry.getKey(); + long dictionaryBusinessId = entry.getKey(); List currConfigAssayMethodList = entry.getValue(); List currConfigAssayMethodIdList = currConfigAssayMethodList.stream().map(m -> m.getId()).collect(Collectors.toList()); ConfigAssayMethodDO configAssayMethod = currConfigAssayMethodList.get(0); // ConfigAssayMethodDO configAssayMethod = sampleTaskAssignContext.getConfigAssayMethodById(key); - DictionaryBusinessDO dictionaryBusinessDO = dictionaryBusinessMapper.selectById(key); + DictionaryBusinessDO dictionaryBusinessDO = dictionaryBusinessMapper.selectById(dictionaryBusinessId); //查询报表模板 ConfigReportTemplateDO configReportTemplate = configReportTemplateMapper.selectLatestConfigReportTemplateByKey(configAssayMethod.getConfigReportTemplateKey()); + + // 筛选出当前业务类型下的所有待分配数据 + List valList = businessAssayTaskDataList.stream() + .filter(f -> currConfigAssayMethodIdList.contains(f.getConfigAssayMethodId())) + .collect(Collectors.toList()); + + if (valList.isEmpty()) { + continue; + } + + // 【核心修改】轮询分配逻辑 + // 不再是为整个组创建一个任务单,而是根据数据量,将数据平均分给 list 中的用户 + for (int i = 0; i < valList.size(); i++) { + BusinessAssayTaskDataDO val = valList.get(i); + + // 1. 确定当前数据分配给哪个用户 (轮询) + AssignAssayUser currentUser = assignAssayUserList.get(i % assignAssayUserCount); + String currentOperatorName = currentUser.getRealName(); + Long currentOperatorId = currentUser.getUserId(); + + // 2. 查找或创建该用户在此业务类型下的任务单 + // 缓存Key:用户ID_业务ID + String cacheKey = currentOperatorId + "_" + dictionaryBusinessId; + BusinessAssayTaskDO businessAssayTaskDO = existingTaskCache.get(cacheKey); + + if (businessAssayTaskDO == null) { + // 缓存没命中,去数据库查该用户是否有进行中的任务 + businessAssayTaskDO = businessAssayTaskMapper.selectAssignInProgressByAssayUserAndAssignUser( + dictionaryBusinessId, currentOperatorName, loginRealname); + + if (businessAssayTaskDO == null) { + // 没有进行中任务,新建 + String taskNo = sequenceUtil.genCode(configAssayMethod.getCodeRule()); + businessAssayTaskDO = new BusinessAssayTaskDO(); + businessAssayTaskDO.setId(IdWorker.getId()); + businessAssayTaskDO.setTaskNo(taskNo); + businessAssayTaskDO.setTaskName(dictionaryBusinessDO.getName()); + + // 设置当前轮询到的操作员 + businessAssayTaskDO.setAssayOperator(currentOperatorName); + businessAssayTaskDO.setAssayOperatorId(currentOperatorId); + + businessAssayTaskDO.setConfigAssayMethodId(configAssayMethod.getId()); + businessAssayTaskDO.setDictionaryBusinessId(dictionaryBusinessId); + businessAssayTaskDO.setDictionaryBusinessKey(configAssayMethod.getDictionaryBusinessKey()); + businessAssayTaskDO.setTaskSourceType(QmsCommonConstant.TASK_ASSIGN); + businessAssayTaskDO.setConfigReportTemplateId(configReportTemplate.getId()); + businessAssayTaskDO.setConfigReportTemplateKey(configReportTemplate.getKey()); + businessAssayTaskDO.setIsIngredients(configAssayMethod.getIsIngredients()); + businessAssayTaskDO.setIngredientsStatus("initial"); + + businessAssayTaskDO.setTaskAssignOperator(loginRealname); + businessAssayTaskDO.setTaskAssignOperatorId(loginUser.getId()); + businessAssayTaskDO.setTaskAssignTime(currentDateTime); + businessAssayTaskDO.setTaskAssignStatus(QmsCommonConstant.IN_PROGRESS); + businessAssayTaskDO.setTaskAssayStatus(QmsCommonConstant.NOT_START); + businessAssayTaskDO.setFinishStatus(QmsCommonConstant.NOT_START); + businessAssayTaskDO.setFlowStatus(QmsCommonConstant.NOT_START); + + saveBusinessAssayTaskList.add(businessAssayTaskDO); + } else { + updateBusinessAssayTaskList.add(businessAssayTaskDO); + } + // 放入缓存,后续同用户同业务类型的直接复用 + existingTaskCache.put(cacheKey, businessAssayTaskDO); + } + + // 3. 更新原始数据状态 + val.setIsAssignTasked(QmsCommonConstant.YES); + val.setAssignTaskTime(currentDateTime); + // 注意:这里也要更新为当前轮询到的操作员,而不是固定的某个人 + val.setAssayOperator(currentOperatorName); + val.setAssayOperatorId(currentOperatorId); + val.setBusinessAssayTaskId(businessAssayTaskDO.getId()); + + // 4. 构建任务明细 + BusinessSubSampleDO businessSubSampleDO = sampleTaskAssignContext.getBusinessSubSampleById(val.getBusinessSubSampleId()); + + BusinessAssayTaskDetailDO businessAssayTaskDetailDO = new BusinessAssayTaskDetailDO(); + businessAssayTaskDetailDO.setBusinessAssayTaskDataId(val.getId()); + businessAssayTaskDetailDO.setBusinessAssayTaskId(businessAssayTaskDO.getId()); + businessAssayTaskDetailDO.setTaskNo(businessAssayTaskDO.getTaskNo()); + businessAssayTaskDetailDO.setSampleId(val.getBusinessSubSampleId()); + businessAssayTaskDetailDO.setSampleCode(businessSubSampleDO.getSampleAssayCode()); + businessAssayTaskDetailDO.setSampleName(businessSubSampleDO.getSampleName()); + businessAssayTaskDetailDO.setDataSourceType(QmsCommonConstant.NORMAL); + // 如果需要全局排序,这里的 sortNo 可能需要重新计算,如果是按任务单内部排序,保持自增即可 + // 由于现在拆分了任务单,每个任务单内部的 sortNo 最好单独维护,这里简单处理为累加(实际可能需按任务单分组后重排) + // 建议:如果在同一个任务单内,sortNo 应该是连续的。由于我们是循环插入,可能需要后期整理,或者在这里维护一个 Map + // 为了简化,这里暂时保持原有逻辑,实际生产中建议在循环结束后按 taskId 分组重新设置 sortNo + + businessAssayTaskDetailList.add(businessAssayTaskDetailDO); + } + + /** + //根据分配 - BusinessAssayTaskDO businessAssayTaskDO = businessAssayTaskMapper.selectAssignInProgressByAssayUserAndAssignUser(key, assignAssayUser.getRealName(), loginRealname); + BusinessAssayTaskDO businessAssayTaskDO = businessAssayTaskMapper.selectAssignInProgressByAssayUserAndAssignUser(dictionaryBusinessId, assignAssayUser.getRealName(), loginRealname); if (businessAssayTaskDO == null) { String taskNo = sequenceUtil.genCode(configAssayMethod.getCodeRule()); @@ -156,13 +258,26 @@ public class SampleTaskAssignManualTypeCmp extends NodeComponent { businessAssayTaskDetailList.add(businessAssayTaskDetailDO); } + **/ } + // 【可选优化】重新整理明细的排序号 (SortNo),确保每个任务单内的明细是 1, 2, 3... + // 因为上面的循环是交叉写入的,可能导致同一个 taskId 的 sortNo 不连续 (如 1, 1, 2, 2...) 如果多个用户交替 + // 实际上上面的逻辑中,同一个 taskId 是由同一个用户产生的,但因为是交叉循环,可能插入顺序是交错的。 + // 最稳妥的方式是按 taskId 分组重排 + Map sortCounterMap = new HashMap<>(); + for (BusinessAssayTaskDetailDO detail : businessAssayTaskDetailList) { + Long taskId = detail.getBusinessAssayTaskId(); + int currentSort = sortCounterMap.getOrDefault(taskId, 0) + 1; + detail.setSortNo(currentSort); + sortCounterMap.put(taskId, currentSort); + } sampleTaskAssignContext.setSaveBusinessAssayTaskList(saveBusinessAssayTaskList); sampleTaskAssignContext.setUpdateBusinessAssayTaskList(updateBusinessAssayTaskList); sampleTaskAssignContext.setBusinessAssayTaskDataList(businessAssayTaskDataList); sampleTaskAssignContext.setBusinessAssayTaskDetailList(businessAssayTaskDetailList); + } @Override diff --git a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/service/SampleTaskAssignServiceImpl.java b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/service/SampleTaskAssignServiceImpl.java index 5b351291..217113fe 100644 --- a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/service/SampleTaskAssignServiceImpl.java +++ b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/business/bus/service/SampleTaskAssignServiceImpl.java @@ -1345,7 +1345,7 @@ public class SampleTaskAssignServiceImpl implements SampleTaskAssignService { @Override @Transactional(rollbackFor = Exception.class) public LiteflowResponse manualTypeAssign(SampleTaskAssignManualTypeParam param) { - if (param.getAssignAssayUser() == null) { + if (CollUtil.isEmpty(param.getAssignAssayUserList())) { throw new ServiceException(1_032_100_000, "无任务分配人员"); } if (CollUtil.isEmpty(param.getAssayTaskDataIdList())) {