diff --git a/src/main/java/a8k/app/dao/type/combination/ProjBuildinInfo.java b/src/main/java/a8k/app/dao/type/combination/ProjBuildInInfo.java similarity index 94% rename from src/main/java/a8k/app/dao/type/combination/ProjBuildinInfo.java rename to src/main/java/a8k/app/dao/type/combination/ProjBuildInInfo.java index 82523bf..6bf5c06 100644 --- a/src/main/java/a8k/app/dao/type/combination/ProjBuildinInfo.java +++ b/src/main/java/a8k/app/dao/type/combination/ProjBuildInInfo.java @@ -19,7 +19,7 @@ import java.util.List; */ @Slf4j @Data -public class ProjBuildinInfo implements Serializable { +public class ProjBuildInInfo implements Serializable { /*基础配置*/ public Integer projId; //项目index public String projName; //项目名称 @@ -49,7 +49,7 @@ public class ProjBuildinInfo implements Serializable { public List optcfg; - public ProjBuildinInfo() {} //for json + public ProjBuildInInfo() {} //for json public A8kOptType getOptType(Integer subProjIndex) { for (OptCfg optCfg : optcfg) { @@ -81,7 +81,7 @@ public class ProjBuildinInfo implements Serializable { } - public ProjBuildinInfo(ProjectBaseInfo baseInfo, List optInfos) { + public ProjBuildInInfo(ProjectBaseInfo baseInfo, List optInfos) { //遍历所有ProjectBaseInfo字段,赋值给ProjBuildinInfo for (var field : baseInfo.getClass().getDeclaredFields()) { if (field.getName().equals("id")) { diff --git a/src/main/java/a8k/app/engineer/service/qatest/ExperimentConsistencyTestingService.java b/src/main/java/a8k/app/engineer/service/qatest/ExperimentConsistencyTestingService.java index d5a314f..88c82ac 100644 --- a/src/main/java/a8k/app/engineer/service/qatest/ExperimentConsistencyTestingService.java +++ b/src/main/java/a8k/app/engineer/service/qatest/ExperimentConsistencyTestingService.java @@ -2,7 +2,7 @@ package a8k.app.engineer.service.qatest; import a8k.OS; import a8k.app.constant.AppConstant; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.dao.type.db.ReactionReport; import a8k.app.engineer.service.executor.EngineerModeActionExecutor; @@ -37,6 +37,8 @@ import a8k.app.type.a8k.state.Tube; import a8k.app.type.error.AppError; import a8k.app.type.exception.AppException; import a8k.app.type.exception.EngineerTaskBreakException; +import a8k.app.type.misc.TubeHolderScanResult; +import a8k.app.type.misc.TubeScanResult; import a8k.app.type.param.type.A8kSamplePos; import a8k.app.type.ui.TubeHolderSetting; import a8k.app.type.ui.TubeSetting; @@ -94,17 +96,17 @@ public class ExperimentConsistencyTestingService { /* * 控制器 */ - final private TubePreProcesModuleCtrlService tubePreProcesModuleCtrlService; + final private TubePreProcesModuleCtrlService tubePreProcesModuleCtrlService; final private TubeFeedingCtrlService tubeFeedingCtrlService; final private TubePreProcessModuleExCtrlService tubePreProcessModuleExCtrlService; final private OptScanModuleCtrlService optScanModuleCtrlService; - final private PlateBoxCtrlService plateBoxCtrlService; - final private TurnableMoveCtrlService turnableMoveCtrlService; - final private LiquidOperationCtrService liquidOperationCtrService; - final private HbotMoveExCtrlService hbotMoveExCtrlService; - private final OptModuleDriver optModuleDriver; - private final HbotMoveCtrlService hbotMoveCtrlService; - private final TipOperationCtrlModule tipOperationCtrlModule; + final private PlateBoxCtrlService plateBoxCtrlService; + final private TurnableMoveCtrlService turnableMoveCtrlService; + final private LiquidOperationCtrService liquidOperationCtrService; + final private HbotMoveExCtrlService hbotMoveExCtrlService; + private final OptModuleDriver optModuleDriver; + private final HbotMoveCtrlService hbotMoveCtrlService; + private final TipOperationCtrlModule tipOperationCtrlModule; private TubeHolderSetting curTubeHolderSetting; private A8kSamplePos samplePos; @@ -179,362 +181,362 @@ public class ExperimentConsistencyTestingService { log.info("开始试剂实验一致性检测"); curTubeHolderSetting = tubeHolderSetting; - actionExecutor.start(this::action); - } - - void docmd(String mark, A8kCmdRunnable runnable, A8kCmdRunnable virtualRunable) throws AppException { - actionExecutor.sleep(2); - actionExecutor.docmd(mark, runnable, virtualRunable); - - } - - void docmd(String mark, A8kCmdRunnable runnable) throws AppException { - UISender.txInfoMsg(log, mark); - actionExecutor.docmd(mark, runnable); - } - - - public void action() { - - try { - doAction(); - } catch (Exception e) { - processException(e); - } - } - - public void processException(Exception e) { - try { - log.error("Catch exception: ", e); - if (!(e instanceof EngineerTaskBreakException)) { - UISender.txErrorPrompt(e); - } - // - // Action - // - if (actionExecutor.isInRealMode()) { - optScanModuleCtrlService.dropPlate(); - tipOperationCtrlModule.dropTip(); - tubeFeedingCtrlService.ejectTubeHolder(); - List all = incubationPlateStateMgr.getAllNotFreeIncubationSubTanks(); - for (IncubationSubTank notFreeTank : all) { - optScanModuleCtrlService.pullPlate(notFreeTank.pos); - optScanModuleCtrlService.dropPlate(); - } - } - // - // State - // - optScanModuleStateMgr.changeOptScanModuleStateToEmpty(); - incubationPlateStateMgr.resetAll(); - } catch (AppException ex) { - log.error("Catch exception: ", e); - UISender.txErrorPrompt(e); - gStateMgrService.setFatalError(ex.error); - } catch (Exception ex) { - log.error("Catch exception: ", e); - UISender.txErrorPrompt(e); - gStateMgrService.setFatalError(new AppError(A8kEcode.SYS_EXCEPTION, ex.getMessage())); - } - - } - - Boolean hasTubeHolder; - TubeFeedingCtrlService.TubeHolderScanResult scanResult; - - public void doAction() throws AppException { - /* - * 1. 核对是否存在试管配置是否只有一个 - * 2. 核对耗材是否充足 - * - * - * 1. 入料 - * 2. 核对试管架类型 - * - * Loop - * 1. 样本准备 - * - * Loop - * 1. 检查孵育盘是否有空闲位(没有空闲位,则等待空闲位) - * 2. 检查是否有孵育完成的样本 (有孵育完成的样本,则进行光学扫描) - * 3. 入板 - * 4. 取样 - * 5. 预反应 - * 6. 滴定 - * - * End: - * 1. 等待所有反应板孵育完成 - */ - - //入料 - hasTubeHolder = false; - docmd("入料", () -> { - hasTubeHolder = tubeFeedingCtrlService.enterTubeHolder(); - }, () -> hasTubeHolder = true); - if (!hasTubeHolder) { - throw AppException.of(A8kEcode.ERROR_OPERATION, "入料超时,未检测到试管架"); - } - - //扫描试管架 - scanResult = null; - docmd("扫描试管架", () -> { - scanResult = tubeFeedingCtrlService.scanTubeHodler(); - }, () -> { - scanResult = new TubeFeedingCtrlService.TubeHolderScanResult(); - for (int i = 0; i < curTubeHolderSetting.tubeSettings.length; i++) { - scanResult.tube[i] = new TubeFeedingCtrlService.TubesScanResult(); - if (!curTubeHolderSetting.tubeSettings[i].projId.isEmpty()) { - scanResult.tube[i].isTubeExist = true; - } - } - }); - //核对试管架信息 - verifyTubeHolderSettingAndTubeHolderScanResult(curTubeHolderSetting, scanResult); - // - A8kTubeHolderType tubeHolderType = A8kTubeHolderType.of(scanResult.tubeHolderType); - if (A8kTubeHolderType.BulletTube1P5.equals(tubeHolderType)) { - samplePos = A8kSamplePos.Bulltube1P5Pos; - } else if (A8kTubeHolderType.BulletTube0P5.equals(tubeHolderType)) { - samplePos = A8kSamplePos.Bulltube0P5Pos; - } else { - throw AppException.of(A8kEcode.APPE_TUBE_HOLDER_TYPE_IS_NOT_SUPPORT, "请使用子弹头1.5ml或者子弹头0.5ml试管架"); - } - - - //构建试管架 - // setTubeHolderDirect - for (int tubeoff = 0; tubeoff < curTubeHolderSetting.tubeSettings.length; tubeoff++) { - TubeSetting tubeSetting = curTubeHolderSetting.tubeSettings[tubeoff]; - if (tubeSetting.projId.isEmpty()) { - continue; - } - Assert.isTrue(scanResult.tube[tubeoff].isTubeExist, String.format("位置[%d]未放入是试管", tubeoff + 1)); - - //移动试管架到预处理位置 - int finalTubeoff = tubeoff; - UISender.txInfoMsg(log, "开始处理第%d个试管", finalTubeoff + 1); - docmd("移动试管到处理位", () -> tubeFeedingCtrlService.moveTubeToPreProcessPos(finalTubeoff)); - - for (int j = 0; j < getRepeatTimes(tubeoff); j++) { - - //尝试处理孵育完成的反应板 - incubationPlateProcess(false); - ProjBuildinInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(expectedProjId); - - //申请耗材 - var consumableInfo = consumablesMgrService.reserveConsumable(projBuildinInfo.reactionFlowType, expectedProjId); - if (consumableInfo == null) { - throw AppException.of(A8kEcode.CODEERROR, "耗材不足?"); //理论上开始阶段已经核对过了耗材数量,此时应该不会不足 - } - consumablesMgrService.useReserveConsumable(consumableInfo); - - //构造项目信息 - ProjExtInfoCard projExtInfoCard = projInfoMgrService.getProjExtInfoCard(consumableInfo.lotid); - ProjBriefInfo projBriefInfo = ProjInfoUtils.buildProjBrefInfo(projBuildinInfo); - - Assert.notNull(projBuildinInfo, "projBuildInInfo is null"); - Assert.notNull(projExtInfoCard, "projExtInfoCard is null"); - - //处理样本 - Tube tube = new Tube(tubeoff); - tube.setIsHighTube(false); - tube.setIsEmergency(false); - tube.setBloodType(tubeSetting.bloodType); - tube.setSampleBarcode(tubeSetting.sampleBarcode); - tube.setUserid(tubeSetting.userid); - tube.setProjInfo(ZList.of(projBriefInfo)); - tube.setProjIds(ZList.of(expectedProjId)); - String sampleId = tubeStateMgrService.newSample(tube); - tube.setSampleId(sampleId); - - - //处理试管 - processTube(tube, tubeoff, consumableInfo, tubeSetting); - if (!tube.getErrors().isEmpty()) { - log.warn("样本异常,跳过当前样本"); - UISender.txErrorMsg(log, tube.getErrors().getFirst(), "样本异常,跳过当前样本"); - break; - } - docmd("HBOT复位", hbotMoveExCtrlService::moveQuickToZero); - } - } - tubeFeedingCtrlService.ejectTubeHolder(); - - incubationPlateProcess(true); - incubationPlateStateMgr.resetAll(); - UISender.txInfoPrompt(log, "试剂实验一致性检测完成"); - } - - private void processTube(Tube tube, Integer offset, ConsumableInfo consumableInfo, TubeSetting tubeSetting) throws AppException { - - ProjBuildinInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(expectedProjId); - ProjExtInfoCard projExtInfoCard = projInfoMgrService.getProjExtInfoCard(consumableInfo.lotid); - - - //拉取一个板夹到孵育盘 - var freeIncubationPos = incubationPlateStateMgr.takeOneIncubationIDLEPos( - (IncubatorPos pos) -> { - incubationPlateStateMgr.syncProjInfo(pos, projBuildinInfo, projExtInfoCard); - incubationPlateStateMgr.syncSampleInfo(pos, tube.getSampleInfo()); - } - ); - - //强制清空一下光学模组和孵育盘 - // optScanModuleCtrlService.dropPlate(); - // optScanModuleCtrlService.pullPlate(freeIncubationPos); - // optScanModuleCtrlService.dropPlate(); - - docmd("丢反应板", optScanModuleCtrlService::dropPlate); - docmd("拉取反应板", () -> optScanModuleCtrlService.pullPlate(freeIncubationPos)); - docmd("丢反应板", optScanModuleCtrlService::dropPlate); - - - // plateBoxCtrlService.pushPlateQuick(consumableInfo.group, freeIncubationPos); - docmd("推入新的反应板", () -> plateBoxCtrlService.pushPlateQuick(consumableInfo.group, freeIncubationPos)); - //移动当前板夹到滴定位 - // turnableMoveCtrlService.trunableMoveToDropLiquidPos(freeIncubationPos); - docmd("移动到滴定位", () -> turnableMoveCtrlService.trunableMoveToDropLiquidPos(freeIncubationPos)); - - - docmd("样本处理", () -> { - try { - liquidOperationCtrService.setProjContext(projBuildinInfo, projExtInfoCard); - var preProcessPos = new PreReactionPos(ConsumableType.SmallBottleBuffer, consumableInfo.group, consumableInfo.pos); - //取tip - tipOperationCtrlModule.tryTakeTip(() -> !actionExecutor.isStopping()); - actionExecutor.sleep(1); - //刺破缓冲液 - hbotMoveExCtrlService.moveToLittleBufferPiercePos(consumableInfo.group, consumableInfo.pos); - //取样品 - Assert.isTrue(!samplePos.equals(A8kSamplePos.EmergencyTubePos), "samplePos cannot be EmergencyTubePos"); - Assert.isTrue(!samplePos.equals(A8kSamplePos.BloodHTubePos), "samplePos cannot be BloodHTubePos"); - Assert.isTrue(!samplePos.equals(A8kSamplePos.BloodSTubePos), "samplePos cannot be BloodSTubePos"); - liquidOperationCtrService.takeSampleToPreReactionPos(samplePos, preProcessPos, takeSampleUl); - actionExecutor.sleep(1); - //取混合液到预反应位 - liquidOperationCtrService.takePreReactionLiquid(preProcessPos); - liquidOperationCtrService.dropLiquidToReactionPlate(); - actionExecutor.sleep(1); - incubationPlateStateMgr.startIncubating(freeIncubationPos, System.currentTimeMillis(), projBuildinInfo.reactionPlateIncubationTimeMin * 60); - actionExecutor.sleep(1); - } catch (AppException e) { - if (e.getError().eq(A8kEcode.APPE_TAKE_SAMPLE_FAIL)) { - hbotMoveExCtrlService.moveQuickToZero(); - tube.setErrors(ZList.of(e.getError())); - incubationPlateStateMgr.resetIncubatorPos(freeIncubationPos); - //丢反应板 - optScanModuleCtrlService.forceDropPlate(freeIncubationPos); - UISender.txErrorMsg(log, e, "取样失败"); - } else { - throw e; - } - } - }, () -> { - incubationPlateStateMgr.startIncubating(freeIncubationPos, System.currentTimeMillis(), projBuildinInfo.reactionPlateIncubationTimeMin * 60); - }); - - - {//开始孵育 - } - } - - - private void incubationPlateProcess(Boolean waittingForAll) throws AppException { - do { - IncubationSubTank tankPos = incubationPlateStateMgr.getOneExpiredPlate(); - if (!waittingForAll) { - if (incubationPlateStateMgr.isHasEnoughIncubationIDLEPos(1) && tankPos == null) { - break; - } - } else { - if (incubationPlateStateMgr.isAllIncubationSubTanksFree()) { - break; - } - } - - if (tankPos != null) { - - //拉取反应板到光学模组 - docmd("拉取反应板到光学模块", () -> {optScanModuleCtrlService.pullPlate(tankPos.getPos());}); - - //设置光学模组状态 - optScanModuleStateMgr.changeOptScanModuleStateToPlateIsReady(tankPos.projInfo, tankPos.toSampleInfo()); - optScanModuleStateMgr.syncProjInfo(tankPos.projBuildinInfo, tankPos.projExtInfoCard); - //复位孵育盘状态 - incubationPlateStateMgr.resetIncubatorPos(tankPos.getPos()); - - // - //光学扫描 - // - - //光学扫描 - optScanModuleStateMgr.changeOptScanModuleStateToScanning(); - doOptScan(); - //丢板 - - docmd("丢弃反应板", optScanModuleCtrlService::dropPlate); - - optScanModuleStateMgr.changeOptScanModuleStateToEmpty(); - } - - actionExecutor.sleep(100); - } while (true); - } - - private void doOptScan() throws AppException { - /* - * HsCrp只有一个项目 - */ - Assert.isTrue(Objects.equals(expectedProjId, 1), "1 != expectedProjId"); - - int subProjIndex = 0; - - A8kOptType optType = optScanModuleStateMgr.getOptScanModule().getProjBuildinInfo().getOptType(subProjIndex); - var buildInInfo = optScanModuleStateMgr.getOptScanModule().getProjBuildinInfo(); - SampleInfo sampleInfo = optScanModuleStateMgr.getOptScanModule().getSampleInfo(); - ProjInfo projInfo = optScanModuleStateMgr.getOptScanModule().getProjInfo(); - - // a8kOptPeakInfo - docmd("光学扫描", () -> { - OptScanResult optScanResult = optScanModuleCtrlService.optScan(buildInInfo, subProjIndex); - ReactionReport.ReactionResult result = A8kPeakAnalyzer.analysisPeakInfo(sampleInfo, projInfo, subProjIndex, optScanResult.analysResult); - - log.info("光学扫描结果: {}", result); - reactionRecordMgrService.addRecord(optScanModuleStateMgr.getOptScanModule().getSampleInfo(), projInfo, ZList.of(optScanResult), ZList.of(result)); - } - , () -> { - OS.hsleep(1000); - } - ); - } - - - - /* - * Utils - */ - - private void verifyTubeHolderSettingAndTubeHolderScanResult(TubeHolderSetting tubeHolderSetting, TubeFeedingCtrlService.TubeHolderScanResult scanResult) throws AppException { - A8kTubeHolderType tubeHolderType = A8kTubeHolderType.of(scanResult.tubeHolderType); - if (!tubeHolderType.equals(A8kTubeHolderType.BulletTube1P5) && !tubeHolderType.equals(A8kTubeHolderType.BulletTube0P5)) { - throw AppException.of(A8kEcode.APPE_TUBE_HOLDER_TYPE_IS_NOT_SUPPORT, "请使用子弹头1.5ml或者子弹头0.5ml试管架"); - } - - for (int i = 0; i < tubeHolderSetting.tubeSettings.length; i++) { - TubeSetting tubeSetting = tubeHolderSetting.tubeSettings[i]; - if (tubeSetting.projId.isEmpty() && !scanResult.tube[i].isTubeExist) { - continue; - } - - if (tubeSetting.projId.isEmpty()) { - throw AppException.of(A8kEcode.APPE_TUBEHOLDER_SETTING_ERROR, String.format("试管[%d]缺少项目配置", i + 1)); - } - - if (!scanResult.tube[i].isTubeExist) { - throw AppException.of(A8kEcode.APPE_TUBEHOLDER_SETTING_ERROR, String.format("位置[%d]未放入是试管", i + 1)); - } - - } + // actionExecutor.start(this::action); } + // + // void docmd(String mark, A8kCmdRunnable runnable, A8kCmdRunnable virtualRunable) throws AppException { + // actionExecutor.sleep(2); + // actionExecutor.docmd(mark, runnable, virtualRunable); + // + // } + // + // void docmd(String mark, A8kCmdRunnable runnable) throws AppException { + // UISender.txInfoMsg(log, mark); + // actionExecutor.docmd(mark, runnable); + // } + // + // + // public void action() { + // + // try { + // doAction(); + // } catch (Exception e) { + // processException(e); + // } + // } + // + // public void processException(Exception e) { + // try { + // log.error("Catch exception: ", e); + // if (!(e instanceof EngineerTaskBreakException)) { + // UISender.txErrorPrompt(e); + // } + // // + // // Action + // // + // if (actionExecutor.isInRealMode()) { + // optScanModuleCtrlService.dropPlate(); + // tipOperationCtrlModule.dropTip(); + // tubeFeedingCtrlService.ejectTubeHolder(); + // List all = incubationPlateStateMgr.getAllNotFreeIncubationSubTanks(); + // for (IncubationSubTank notFreeTank : all) { + // optScanModuleCtrlService.pullPlate(notFreeTank.pos); + // optScanModuleCtrlService.dropPlate(); + // } + // } + // // + // // State + // // + // optScanModuleStateMgr.changeOptScanModuleStateToEmpty(); + // incubationPlateStateMgr.resetAll(); + // } catch (AppException ex) { + // log.error("Catch exception: ", e); + // UISender.txErrorPrompt(e); + // gStateMgrService.setFatalError(ex.error); + // } catch (Exception ex) { + // log.error("Catch exception: ", e); + // UISender.txErrorPrompt(e); + // gStateMgrService.setFatalError(new AppError(A8kEcode.SYS_EXCEPTION, ex.getMessage())); + // } + // + // } + // + // Boolean hasTubeHolder; + // TubeHolderScanResult scanResult; + // + // public void doAction() throws AppException { + // /* + // * 1. 核对是否存在试管配置是否只有一个 + // * 2. 核对耗材是否充足 + // * + // * + // * 1. 入料 + // * 2. 核对试管架类型 + // * + // * Loop + // * 1. 样本准备 + // * + // * Loop + // * 1. 检查孵育盘是否有空闲位(没有空闲位,则等待空闲位) + // * 2. 检查是否有孵育完成的样本 (有孵育完成的样本,则进行光学扫描) + // * 3. 入板 + // * 4. 取样 + // * 5. 预反应 + // * 6. 滴定 + // * + // * End: + // * 1. 等待所有反应板孵育完成 + // */ + // + // //入料 + // hasTubeHolder = false; + // docmd("入料", () -> { + // hasTubeHolder = tubeFeedingCtrlService.enterTubeHolder(); + // }, () -> hasTubeHolder = true); + // if (!hasTubeHolder) { + // throw AppException.of(A8kEcode.ERROR_OPERATION, "入料超时,未检测到试管架"); + // } + // + // //扫描试管架 + // scanResult = null; + // docmd("扫描试管架", () -> { + // scanResult = tubeFeedingCtrlService.scanTubeHodler(); + // }, () -> { + // scanResult = new TubeHolderScanResult(); + // for (int i = 0; i < curTubeHolderSetting.tubeSettings.length; i++) { + // scanResult.tube[i] = new TubeScanResult(); + // if (!curTubeHolderSetting.tubeSettings[i].projId.isEmpty()) { + // scanResult.tube[i].isTubeExist = true; + // } + // } + // }); + // //核对试管架信息 + // verifyTubeHolderSettingAndTubeHolderScanResult(curTubeHolderSetting, scanResult); + // // + // A8kTubeHolderType tubeHolderType = A8kTubeHolderType.of(scanResult.tubeHolderType); + // if (A8kTubeHolderType.BulletTube1P5.equals(tubeHolderType)) { + // samplePos = A8kSamplePos.Bulltube1P5Pos; + // } else if (A8kTubeHolderType.BulletTube0P5.equals(tubeHolderType)) { + // samplePos = A8kSamplePos.Bulltube0P5Pos; + // } else { + // throw AppException.of(A8kEcode.APPE_TUBE_HOLDER_TYPE_IS_NOT_SUPPORT, "请使用子弹头1.5ml或者子弹头0.5ml试管架"); + // } + // + // + // //构建试管架 + // // setTubeHolderDirect + // for (int tubeoff = 0; tubeoff < curTubeHolderSetting.tubeSettings.length; tubeoff++) { + // TubeSetting tubeSetting = curTubeHolderSetting.tubeSettings[tubeoff]; + // if (tubeSetting.projId.isEmpty()) { + // continue; + // } + // Assert.isTrue(scanResult.tube[tubeoff].isTubeExist, String.format("位置[%d]未放入是试管", tubeoff + 1)); + // + // //移动试管架到预处理位置 + // int finalTubeoff = tubeoff; + // UISender.txInfoMsg(log, "开始处理第%d个试管", finalTubeoff + 1); + // docmd("移动试管到处理位", () -> tubeFeedingCtrlService.moveTubeToPreProcessPos(finalTubeoff)); + // + // for (int j = 0; j < getRepeatTimes(tubeoff); j++) { + // + // //尝试处理孵育完成的反应板 + // incubationPlateProcess(false); + // ProjBuildInInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(expectedProjId); + // + // //申请耗材 + // var consumableInfo = consumablesMgrService.reserveConsumable(projBuildinInfo.reactionFlowType, expectedProjId); + // if (consumableInfo == null) { + // throw AppException.of(A8kEcode.CODEERROR, "耗材不足?"); //理论上开始阶段已经核对过了耗材数量,此时应该不会不足 + // } + // consumablesMgrService.useReserveConsumable(consumableInfo); + // + // //构造项目信息 + // ProjExtInfoCard projExtInfoCard = projInfoMgrService.getProjExtInfoCard(consumableInfo.lotid); + // ProjBriefInfo projBriefInfo = ProjInfoUtils.buildProjBrefInfo(projBuildinInfo); + // + // Assert.notNull(projBuildinInfo, "projBuildInInfo is null"); + // Assert.notNull(projExtInfoCard, "projExtInfoCard is null"); + // + // //处理样本 + // Tube tube = new Tube(tubeoff); + // tube.setIsHighTube(false); + // tube.setIsEmergency(false); + // tube.setBloodType(tubeSetting.bloodType); + // tube.setSampleBarcode(tubeSetting.sampleBarcode); + // tube.setUserid(tubeSetting.userid); + // tube.setProjInfo(ZList.of(projBriefInfo)); + // tube.setProjIds(ZList.of(expectedProjId)); + // String sampleId = tubeStateMgrService.newSample(tube); + // tube.setSampleId(sampleId); + // + // + // //处理试管 + // processTube(tube, tubeoff, consumableInfo, tubeSetting); + // if (!tube.getErrors().isEmpty()) { + // log.warn("样本异常,跳过当前样本"); + // UISender.txErrorMsg(log, tube.getErrors().getFirst(), "样本异常,跳过当前样本"); + // break; + // } + // docmd("HBOT复位", hbotMoveExCtrlService::moveQuickToZero); + // } + // } + // tubeFeedingCtrlService.ejectTubeHolder(); + // + // incubationPlateProcess(true); + // incubationPlateStateMgr.resetAll(); + // UISender.txInfoPrompt(log, "试剂实验一致性检测完成"); + // } + // + // private void processTube(Tube tube, Integer offset, ConsumableInfo consumableInfo, TubeSetting tubeSetting) throws AppException { + // + // ProjBuildInInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(expectedProjId); + // ProjExtInfoCard projExtInfoCard = projInfoMgrService.getProjExtInfoCard(consumableInfo.lotid); + // + // + // //拉取一个板夹到孵育盘 + // var freeIncubationPos = incubationPlateStateMgr.takeOneIncubationIDLEPos( + // (IncubatorPos pos) -> { + // incubationPlateStateMgr.syncProjInfo(pos, projBuildinInfo, projExtInfoCard); + // incubationPlateStateMgr.syncSampleInfo(pos, tube.getSampleInfo()); + // } + // ); + // + // //强制清空一下光学模组和孵育盘 + // // optScanModuleCtrlService.dropPlate(); + // // optScanModuleCtrlService.pullPlate(freeIncubationPos); + // // optScanModuleCtrlService.dropPlate(); + // + // docmd("丢反应板", optScanModuleCtrlService::dropPlate); + // docmd("拉取反应板", () -> optScanModuleCtrlService.pullPlate(freeIncubationPos)); + // docmd("丢反应板", optScanModuleCtrlService::dropPlate); + // + // + // // plateBoxCtrlService.pushPlateQuick(consumableInfo.group, freeIncubationPos); + // docmd("推入新的反应板", () -> plateBoxCtrlService.pushPlateQuick(consumableInfo.group, freeIncubationPos)); + // //移动当前板夹到滴定位 + // // turnableMoveCtrlService.trunableMoveToDropLiquidPos(freeIncubationPos); + // docmd("移动到滴定位", () -> turnableMoveCtrlService.trunableMoveToDropLiquidPos(freeIncubationPos)); + // + // + // docmd("样本处理", () -> { + // try { + // liquidOperationCtrService.setProjContext(projBuildinInfo, projExtInfoCard); + // var preProcessPos = new PreReactionPos(ConsumableType.SmallBottleBuffer, consumableInfo.group, consumableInfo.pos); + // //取tip + // tipOperationCtrlModule.tryTakeTip(() -> !actionExecutor.isStopping()); + // actionExecutor.sleep(1); + // //刺破缓冲液 + // hbotMoveExCtrlService.moveToLittleBufferPiercePos(consumableInfo.group, consumableInfo.pos); + // //取样品 + // Assert.isTrue(!samplePos.equals(A8kSamplePos.EmergencyTubePos), "samplePos cannot be EmergencyTubePos"); + // Assert.isTrue(!samplePos.equals(A8kSamplePos.BloodHTubePos), "samplePos cannot be BloodHTubePos"); + // Assert.isTrue(!samplePos.equals(A8kSamplePos.BloodSTubePos), "samplePos cannot be BloodSTubePos"); + // liquidOperationCtrService.takeSampleToPreReactionPos(samplePos, preProcessPos, takeSampleUl); + // actionExecutor.sleep(1); + // //取混合液到预反应位 + // liquidOperationCtrService.takePreReactionLiquid(preProcessPos); + // liquidOperationCtrService.dropLiquidToReactionPlate(); + // actionExecutor.sleep(1); + // incubationPlateStateMgr.startIncubating(freeIncubationPos, System.currentTimeMillis(), projBuildinInfo.reactionPlateIncubationTimeMin * 60); + // actionExecutor.sleep(1); + // } catch (AppException e) { + // if (e.getError().eq(A8kEcode.APPE_TAKE_SAMPLE_FAIL)) { + // hbotMoveExCtrlService.moveQuickToZero(); + // tube.setErrors(ZList.of(e.getError())); + // incubationPlateStateMgr.resetIncubatorPos(freeIncubationPos); + // //丢反应板 + // optScanModuleCtrlService.forceDropPlate(freeIncubationPos); + // UISender.txErrorMsg(log, e, "取样失败"); + // } else { + // throw e; + // } + // } + // }, () -> { + // incubationPlateStateMgr.startIncubating(freeIncubationPos, System.currentTimeMillis(), projBuildinInfo.reactionPlateIncubationTimeMin * 60); + // }); + // + // + // {//开始孵育 + // } + // } + // + // + // private void incubationPlateProcess(Boolean waittingForAll) throws AppException { + // do { + // IncubationSubTank tankPos = incubationPlateStateMgr.getOneExpiredPlate(); + // if (!waittingForAll) { + // if (incubationPlateStateMgr.isHasEnoughIncubationIDLEPos(1) && tankPos == null) { + // break; + // } + // } else { + // if (incubationPlateStateMgr.isAllIncubationSubTanksFree()) { + // break; + // } + // } + // + // if (tankPos != null) { + // + // //拉取反应板到光学模组 + // docmd("拉取反应板到光学模块", () -> {optScanModuleCtrlService.pullPlate(tankPos.getPos());}); + // + // //设置光学模组状态 + // optScanModuleStateMgr.changeOptScanModuleStateToPlateIsReady(tankPos.projInfo, tankPos.toSampleInfo()); + // optScanModuleStateMgr.syncProjInfo(tankPos.projBuildinInfo, tankPos.projExtInfoCard); + // //复位孵育盘状态 + // incubationPlateStateMgr.resetIncubatorPos(tankPos.getPos()); + // + // // + // //光学扫描 + // // + // + // //光学扫描 + // optScanModuleStateMgr.changeOptScanModuleStateToScanning(); + // doOptScan(); + // //丢板 + // + // docmd("丢弃反应板", optScanModuleCtrlService::dropPlate); + // + // optScanModuleStateMgr.changeOptScanModuleStateToEmpty(); + // } + // + // actionExecutor.sleep(100); + // } while (true); + // } + // + // private void doOptScan() throws AppException { + // /* + // * HsCrp只有一个项目 + // */ + // Assert.isTrue(Objects.equals(expectedProjId, 1), "1 != expectedProjId"); + // + // int subProjIndex = 0; + // + // A8kOptType optType = optScanModuleStateMgr.getOptScanModule().getProjBuildinInfo().getOptType(subProjIndex); + // var buildInInfo = optScanModuleStateMgr.getOptScanModule().getProjBuildinInfo(); + // SampleInfo sampleInfo = optScanModuleStateMgr.getOptScanModule().getSampleInfo(); + // ProjInfo projInfo = optScanModuleStateMgr.getOptScanModule().getProjInfo(); + // + // // a8kOptPeakInfo + // docmd("光学扫描", () -> { + // OptScanResult optScanResult = optScanModuleCtrlService.optScan(buildInInfo, subProjIndex); + // ReactionReport.ReactionResult result = A8kPeakAnalyzer.analysisPeakInfo(sampleInfo, projInfo, subProjIndex, optScanResult.analysResult); + // + // log.info("光学扫描结果: {}", result); + // reactionRecordMgrService.addRecord(optScanModuleStateMgr.getOptScanModule().getSampleInfo(), projInfo, ZList.of(optScanResult), ZList.of(result)); + // } + // , () -> { + // OS.hsleep(1000); + // } + // ); + // } + // + // + // + // /* + // * Utils + // */ + // + // private void verifyTubeHolderSettingAndTubeHolderScanResult(TubeHolderSetting tubeHolderSetting, TubeHolderScanResult scanResult) throws AppException { + // A8kTubeHolderType tubeHolderType = A8kTubeHolderType.of(scanResult.tubeHolderType); + // if (!tubeHolderType.equals(A8kTubeHolderType.BulletTube1P5) && !tubeHolderType.equals(A8kTubeHolderType.BulletTube0P5)) { + // throw AppException.of(A8kEcode.APPE_TUBE_HOLDER_TYPE_IS_NOT_SUPPORT, "请使用子弹头1.5ml或者子弹头0.5ml试管架"); + // } + // + // for (int i = 0; i < tubeHolderSetting.tubeSettings.length; i++) { + // TubeSetting tubeSetting = tubeHolderSetting.tubeSettings[i]; + // if (tubeSetting.projId.isEmpty() && !scanResult.tube[i].isTubeExist) { + // continue; + // } + // + // if (tubeSetting.projId.isEmpty()) { + // throw AppException.of(A8kEcode.APPE_TUBEHOLDER_SETTING_ERROR, String.format("试管[%d]缺少项目配置", i + 1)); + // } + // + // if (!scanResult.tube[i].isTubeExist) { + // throw AppException.of(A8kEcode.APPE_TUBEHOLDER_SETTING_ERROR, String.format("位置[%d]未放入是试管", i + 1)); + // } + // + // } + // } } diff --git a/src/main/java/a8k/app/hardware/type/A8kEcode.java b/src/main/java/a8k/app/hardware/type/A8kEcode.java index d08cfd1..031d2e1 100644 --- a/src/main/java/a8k/app/hardware/type/A8kEcode.java +++ b/src/main/java/a8k/app/hardware/type/A8kEcode.java @@ -90,6 +90,7 @@ public enum A8kEcode { APPE_SCAN_TUBEHOLDER_TYPE_TIMEOUT(200),//扫描试管架类型超时 APPE_TUBE_HOLDER_TYPE_IS_NOT_SUPPORT(201),//试管架类型不支持 APPE_INFEED_OVERTIME_FAIL(202),//入料超时失败 + APPE_TUBEHOLDER_IS_EMPTY(203),//试管架中没有试管 //样本处理过程中的错误 APPE_PUT_TIP_FAIL(210),//丢弃Tip失败 @@ -110,8 +111,8 @@ public enum A8kEcode { APPE_A8K_PROJ_CARD_EXPIRYED(301), //ID卡过期 APPE_A8K_PROJ_ID_IS_EMPTY(302), //项目ID为空 PROJ_CARD_ERROR_WRONG_UNSUPPORTED(303), //项目不支持 - APPE_PULLERM_INIT_POS_ERROR(305), //初始化阶段,拉板电机没有处于零点位置 - APPE_PUSHERM_INIT_POS_ERROR(306), //初始化阶段,推板电机没有处于零点位置 + APPE_PULLER_MOTOR_INIT_POS_ERROR(305), //初始化阶段,拉板电机没有处于零点位置 + APPE_PUSHER_MOTOR_INIT_POS_ERROR(306), //初始化阶段,推板电机没有处于零点位置 APPE_PLATE_STUCK_DETECTOR_SENSOR_TRIGGER(307), //卡板检测传感器触发 APPE_TUBE_X_CHANNEL_IS_NOT_EMPTY(308), //试管架通道有异物 APPE_PLATE_BOX_NOT_COVER(309), //板夹仓未盖 @@ -154,8 +155,8 @@ public enum A8kEcode { LOW_ERROR_DEVICE_IS_BUSY(1104), LOW_ERROR_DEVICE_IS_OFFLINE(1105), LOW_ERROR_OVERTIME(1106), - LOW_ERROR_NOACK(1107), - LOW_ERROR_ERRORACK(1108), + LOW_ERROR_NO_ACK(1107), + LOW_ERROR_ERROR_ACK(1108), LOW_ERROR_DEVICE_OFFLINE(1109), LOW_ERROR_SUBDEVICE_OVERTIME(1111), LOW_ERROR_BUFFER_NOT_ENOUGH(1112), @@ -163,12 +164,12 @@ public enum A8kEcode { LOW_ERROR_CHECKCODE_IS_ERROR(1115), LOW_ERROR_ILLEGAL_OPERATION(1116), LOW_ERROR_ACTION_OVERTIME(1117), - LOW_ERROR_MODULE_OPEATION_BREAK_BY_USER(1202), + LOW_ERROR_MODULE_OPERATION_BREAK_BY_USER(1202), LOW_ERROR_MODULE_NOT_FIND_REG(1207), LOW_ERROR_XYMOTOR_X_FIND_ZERO_EDGE_FAIL(1306), LOW_ERROR_XYMOTOR_Y_FIND_ZERO_EDGE_FAIL(1307), LOW_ERROR_XYMOTOR_NOT_ENABLE(1308), - LOW_ERROR_XYMOTOR_TARGET_POS_OUTOF_RANGE(1309), + LOW_ERROR_XYMOTOR_TARGET_POS_OUT_OF_RANGE(1309), LOW_ERROR_XYMOTOR_NOT_MOVE_TO_ZERO(1310), LOW_ERROR_PIPETTE_ERROR_NO_ERROR(1400), LOW_ERROR_PIPETTE_ERROR_INIT_FAIL(1401), @@ -195,7 +196,7 @@ public enum A8kEcode { LOW_ERROR_PIPETTE_ERROR_NO_TIP_WHEN_LLD(1422), LOW_ERROR_PIPETTE_ERROR_TIPISLOAD_WHEN_LLD_PREPARE(1500), - LOW_ERROR_PIPETTE_ERROR_UNINITED(1501), + LOW_ERROR_PIPETTE_ERROR_UNINITIALIZED(1501), LOW_ERROR_PIPETTE_ERROR_NOT_LLD_PREPARE(1502), LOW_ERROR_PIPETTE_ERROR_PUMP_LOAD_VAL_IS_NOT_EMPTY(1503), LOW_ERROR_PIPETTE_LLD_ERROR_NO_LIQUID_DETECTED(1504), @@ -210,7 +211,7 @@ public enum A8kEcode { LOW_ERROR_STEP_MOTOR_OVER_VOLTAGE(1603), LOW_ERROR_STEP_MOTOR_RUN_OVERTIME(1604), LOW_ERROR_STEP_MOTOR_NOT_ENABLE(1605), - LOW_ERROR_STEP_MOTOR_IOINDEX_OUT_OF_RANGE(1606), + LOW_ERROR_STEP_MOTOR_IO_INDEX_OUT_OF_RANGE(1606), LOW_ERROR_STEP_MOTOR_SUBIC_RESET(1607), LOW_ERROR_STEP_MOTOR_DRV_ERR(1608), LOW_ERROR_STEP_MOTOR_UV_CP(1609), @@ -233,7 +234,7 @@ public enum A8kEcode { // // 底层扩展错误码,由java定义 // - LOW_EXT_ERROR_UNKOWN_INDEX_ERROR(5000), //代码错误,未知错误 + LOW_EXT_ERROR_UNKNOWN_INDEX_ERROR(5000), //代码错误,未知错误 LOW_EXT_ERROR_CMD_NOT_SUPPORT(5001), //代码错误,未知错误 LOW_EXT_ERROR_MOTOR_AT_WRONG_POS(5002),//电机在错误的位置 ; @@ -253,8 +254,8 @@ public enum A8kEcode { } } log.error("未知错误码:{}", index); - A8kEcode.LOW_EXT_ERROR_UNKOWN_INDEX_ERROR.rawindex = index; - return A8kEcode.LOW_EXT_ERROR_UNKOWN_INDEX_ERROR; + A8kEcode.LOW_EXT_ERROR_UNKNOWN_INDEX_ERROR.rawindex = index; + return A8kEcode.LOW_EXT_ERROR_UNKNOWN_INDEX_ERROR; } diff --git a/src/main/java/a8k/app/i18n/Internationalization.java b/src/main/java/a8k/app/i18n/Internationalization.java index 0a1cbbc..68349b9 100644 --- a/src/main/java/a8k/app/i18n/Internationalization.java +++ b/src/main/java/a8k/app/i18n/Internationalization.java @@ -20,6 +20,7 @@ public class Internationalization { case APPE_ADD_EMERGENCY_ACTION_IS_NOT_ALLOWED_WHEN_WORKING -> "添加急诊样本失败,设备正在运行中"; case APPE_DEVICE_IS_IN_FATAL_ERROR -> "设备处于严重错误,请关闭电源重启设备"; case APPE_SCAN_TUBEHOLDER_TYPE_TIMEOUT -> "扫描试管架类型超时"; + case APPE_TUBEHOLDER_IS_EMPTY -> "试管架是空的"; case APPE_TUBE_HOLDER_TYPE_IS_NOT_SUPPORT -> "试管架类型不支持"; case APPE_INFEED_OVERTIME_FAIL -> "入料超时失败"; case APPE_PUT_TIP_FAIL -> "丢弃Tip失败"; @@ -32,8 +33,8 @@ public class Internationalization { case APPE_A8K_PROJ_CARD_EXPIRYED -> "ID卡过期"; case APPE_A8K_PROJ_ID_IS_EMPTY -> "项目ID为空"; case PROJ_CARD_ERROR_WRONG_UNSUPPORTED -> "项目不支持"; - case APPE_PULLERM_INIT_POS_ERROR -> "初始化阶段,拉板电机没有处于零点位置"; - case APPE_PUSHERM_INIT_POS_ERROR -> "初始化阶段,推板电机没有处于零点位置"; + case APPE_PULLER_MOTOR_INIT_POS_ERROR -> "初始化阶段,拉板电机没有处于零点位置"; + case APPE_PUSHER_MOTOR_INIT_POS_ERROR -> "初始化阶段,推板电机没有处于零点位置"; case APPE_PLATE_STUCK_DETECTOR_SENSOR_TRIGGER -> "卡板检测传感器触发"; case APPE_TUBE_X_CHANNEL_IS_NOT_EMPTY -> "试管架通道有异物"; case APPE_PLATE_BOX_NOT_COVER -> "板夹仓未盖"; diff --git a/src/main/java/a8k/app/service/analyzer/A8kIdCardDataParseService.java b/src/main/java/a8k/app/service/analyzer/A8kIdCardDataParseService.java index 7e0c8ed..dca2f7f 100644 --- a/src/main/java/a8k/app/service/analyzer/A8kIdCardDataParseService.java +++ b/src/main/java/a8k/app/service/analyzer/A8kIdCardDataParseService.java @@ -1,12 +1,10 @@ package a8k.app.service.analyzer; -import a8k.app.dao.ProjectBaseInfoDao; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.service.data.ProjInfoMgrService; import a8k.app.type.a8k.optfn.A8kNormalFn; import a8k.app.hardware.type.A8kEcode; import a8k.app.type.a8k.optfn.A8kOptX; -import a8k.app.dao.type.db.ProjectBaseInfo; import a8k.app.type.a8k.optfn.A8kPiecewiseFn; import a8k.app.type.a8k.optfn.A8kFnType; import a8k.app.type.a8k.proj.A8kResultUnit; @@ -14,7 +12,6 @@ import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.type.error.AppError; import a8k.app.type.exception.AppException; import a8k.app.utils.ZDateUtils; -import jakarta.annotation.Resource; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -244,7 +241,7 @@ public class A8kIdCardDataParseService { ASSERT_IS_TRUE(idcard.lotId.length() == 8, "PARSE LOTID IS ERROR"); ASSERT_IS_TRUE(!idcard.projName.isEmpty(), "PARSE PROJNAME IS ERROR"); - ProjBuildinInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(idcard.projId); + ProjBuildInInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(idcard.projId); ASSERT_IS_TRUE(projBuildinInfo != null, A8kEcode.PROJ_CARD_ERROR_WRONG_UNSUPPORTED, "PROJECT ID %d NOT SUPPORTED", idcard.projId); if (idcard.projShortName == null || idcard.projShortName.isEmpty()) { idcard.projShortName = projBuildinInfo.getProjShortName(); @@ -367,7 +364,7 @@ public class A8kIdCardDataParseService { private void parseAndCheckFn(ProjExtInfoCard idcard) throws AppException { - ProjBuildinInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(idcard.projId); + ProjBuildInInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(idcard.projId); ASSERT_IS_TRUE(projBuildinInfo != null, A8kEcode.PROJ_CARD_ERROR_WRONG_UNSUPPORTED, "PROJECT ID %d NOT FOUND", idcard.projId); diff --git a/src/main/java/a8k/app/service/analyzer/ConsumableStateAnalyzerService.java b/src/main/java/a8k/app/service/analyzer/ConsumableStateAnalyzerService.java index f6f3b4c..38d22d1 100644 --- a/src/main/java/a8k/app/service/analyzer/ConsumableStateAnalyzerService.java +++ b/src/main/java/a8k/app/service/analyzer/ConsumableStateAnalyzerService.java @@ -5,10 +5,8 @@ import a8k.app.service.statemgr.ConsumablesMgrService; import a8k.app.type.a8k.state.TubeHolderInfo; import a8k.app.type.a8k.state.TubeInfo; import a8k.app.type.exception.AppException; -import a8k.app.type.a8k.state.Tube; -import a8k.app.type.a8k.state.TubeHolder; import a8k.app.service.data.ProjInfoMgrService; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.utils.ZJsonHelper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -37,7 +35,7 @@ public class ConsumableStateAnalyzerService { void assginProjInfo(ConsumableStatInfo info) { ProjInfoMgrService projInfoMgrService = SpringBootBeanUtil.getBean(ProjInfoMgrService.class); - ProjBuildinInfo projBuildinInfo = null; + ProjBuildInInfo projBuildinInfo = null; try { projBuildinInfo = projInfoMgrService.getProjBuildInInfo(info.projId); info.projShortName = projBuildinInfo.projShortName; diff --git a/src/main/java/a8k/app/service/background/ProjIDCardCtrlAndMonitorService.java b/src/main/java/a8k/app/service/background/ProjIDCardCtrlAndMonitorService.java index 9b0d1f9..6869058 100644 --- a/src/main/java/a8k/app/service/background/ProjIDCardCtrlAndMonitorService.java +++ b/src/main/java/a8k/app/service/background/ProjIDCardCtrlAndMonitorService.java @@ -13,7 +13,7 @@ import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.type.exception.AppException; import a8k.app.hardware.channel.A8kCanBusService; import a8k.app.service.analyzer.A8kIdCardDataParseService; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.utils.ZWorkQueue; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; @@ -111,7 +111,7 @@ public class ProjIDCardCtrlAndMonitorService { //解析ID卡信息 try { mountedIdCardInfo = idCardDataParseService.parseAndCheck(data); - ProjBuildinInfo buildinInfo = projInfoMgrService.getProjBuildInInfo(mountedIdCardInfo.projId); + ProjBuildInInfo buildinInfo = projInfoMgrService.getProjBuildInInfo(mountedIdCardInfo.projId); mountedIdCardInfo.color = buildinInfo.color; eventBus.pushEvent(new AppIDCardMountEvent(mountedIdCardInfo)); diff --git a/src/main/java/a8k/app/service/data/ProjIdCardInfoMgrService.java b/src/main/java/a8k/app/service/data/ProjIdCardInfoMgrService.java index 010ea8e..444e6c8 100644 --- a/src/main/java/a8k/app/service/data/ProjIdCardInfoMgrService.java +++ b/src/main/java/a8k/app/service/data/ProjIdCardInfoMgrService.java @@ -14,7 +14,7 @@ import a8k.app.service.statemgr.GStateMgrService; import a8k.app.type.a8k.proj.A8kProjInfoCardBreif; import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.dao.type.common.CommonPage; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.service.utils.ZAppChecker; import a8k.app.utils.DoubleUtils; import jakarta.annotation.Resource; @@ -120,7 +120,7 @@ public class ProjIdCardInfoMgrService { // public List verifyProjExtInfoCard(ProjExtInfoCard projExtInfoCard) throws AppException { - ProjBuildinInfo projBuildinInfo; + ProjBuildInInfo projBuildinInfo; List ecodeList = new ArrayList<>(); try { diff --git a/src/main/java/a8k/app/service/data/ProjInfoMgrService.java b/src/main/java/a8k/app/service/data/ProjInfoMgrService.java index 6e72cfb..591fea3 100644 --- a/src/main/java/a8k/app/service/data/ProjInfoMgrService.java +++ b/src/main/java/a8k/app/service/data/ProjInfoMgrService.java @@ -10,7 +10,7 @@ import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.dao.type.db.ProjectBaseInfo; import a8k.app.type.exception.AppException; import a8k.app.service.background.ProjIDCardCtrlAndMonitorService; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.service.utils.ZAppChecker; import a8k.app.utils.ZJsonHelper; import jakarta.annotation.PostConstruct; @@ -34,32 +34,32 @@ public class ProjInfoMgrService { ProjOptInfoDao projOptInfoDao; - public ProjBuildinInfo getProjBuildInInfo(Integer projId) throws AppException { + public ProjBuildInInfo getProjBuildInInfo(Integer projId) throws AppException { var projBaseInfo = projectBaseInfoDao.findByProjId(projId); var projOptInfos = projOptInfoDao.findByProjIndex(projId); ZAppChecker.notNull(projBaseInfo, A8kEcode.PROJ_CARD_ERROR_WRONG_UNSUPPORTED, "PROJ:%d IS NOT SUPPORTED", projId); ZAppChecker.notEmpty(projOptInfos, A8kEcode.PROJ_CARD_ERROR_BUILD_IN_PROJ_INFO_ERROR, "PROJ:%d OPT CONFIG IS NOT EXIST", projId); ZAppChecker.check(projOptInfos.size() == projBaseInfo.subProjNum, A8kEcode.PROJ_CARD_ERROR_BUILD_IN_PROJ_INFO_ERROR, "PROJ:%d OPT CONFIG IS NOT MATCH", projId); - return new ProjBuildinInfo(projBaseInfo, projOptInfos); + return new ProjBuildInInfo(projBaseInfo, projOptInfos); } - public List getProjBuildInInfo(List projIds) throws AppException { - List projBuildinInfos = new ArrayList<>(); + public List getProjBuildInInfo(List projIds) throws AppException { + List projBuildInInfos = new ArrayList<>(); for (Integer projId : projIds) { - projBuildinInfos.add(getProjBuildInInfo(projId)); + projBuildInInfos.add(getProjBuildInInfo(projId)); } - return projBuildinInfos; + return projBuildInInfos; } - public List getAllProjBuildInInfo() throws AppException { - List projBuildinInfos = new ArrayList<>(); + public List getAllProjBuildInInfo() throws AppException { + List projBuildInInfos = new ArrayList<>(); List projBInfos = projectBaseInfoDao.getAll(); for (ProjectBaseInfo projBInfo : projBInfos) { - projBuildinInfos.add(getProjBuildInInfo(projBInfo.projId)); + projBuildInInfos.add(getProjBuildInInfo(projBInfo.projId)); } - return projBuildinInfos; + return projBuildInInfos; } public ProjExtInfoCard getProjExtInfoCard(String lotid) { @@ -70,7 +70,7 @@ public class ProjInfoMgrService { var service = SpringBootBeanUtil.getBean(ProjIDCardCtrlAndMonitorService.class); return service.getMountedIdCardInfo(); } - public ProjBuildinInfo getProjBuildInInfoByMountedCard() throws AppException { + public ProjBuildInInfo getProjBuildInInfoByMountedCard() throws AppException { var mountedIdCardInfo = getMountedProjInfoCard(); if(mountedIdCardInfo == null){ return null; diff --git a/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java b/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java index 0543a9c..21eae89 100644 --- a/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java +++ b/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java @@ -1,7 +1,7 @@ package a8k.app.service.lowerctrl; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.hardware.driver.PipetteCtrlDriverV2; import a8k.app.hardware.type.A8kEcode; @@ -49,11 +49,11 @@ public class LiquidOperationCtrService { private final TipOperationCtrlModule tipOperationCtrlModule; - ProjBuildinInfo projBuildinInfo; + ProjBuildInInfo projBuildinInfo; ProjExtInfoCard projExtInfo; - synchronized public void setProjContext(ProjBuildinInfo projBuildinInfo, ProjExtInfoCard projExtInfo) { + synchronized public void setProjContext(ProjBuildInInfo projBuildinInfo, ProjExtInfoCard projExtInfo) { this.projBuildinInfo = projBuildinInfo; this.projExtInfo = projExtInfo; } diff --git a/src/main/java/a8k/app/service/lowerctrl/OptScanModuleCtrlService.java b/src/main/java/a8k/app/service/lowerctrl/OptScanModuleCtrlService.java index bf960a4..34d5c7a 100644 --- a/src/main/java/a8k/app/service/lowerctrl/OptScanModuleCtrlService.java +++ b/src/main/java/a8k/app/service/lowerctrl/OptScanModuleCtrlService.java @@ -15,7 +15,7 @@ import a8k.app.dao.type.db.OptRawScanData; import a8k.app.type.a8k.opt.A8kOptType; import a8k.app.type.a8k.pos.IncubatorPos; import a8k.app.type.exception.AppException; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.hardware.utils.OptGainConvert; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -206,7 +206,7 @@ public class OptScanModuleCtrlService { return rawData; } - public OptScanResult optScan(ProjBuildinInfo projBuildinInfo, Integer subProjIndex, Boolean autoAmpl) throws AppException { + public OptScanResult optScan(ProjBuildInInfo projBuildinInfo, Integer subProjIndex, Boolean autoAmpl) throws AppException { UISender.txInfoMsg(log, "光学扫描"); A8kOptCurveAnalyzer a8KOptCurveAnalyzer = new A8kOptCurveAnalyzer(); @@ -223,7 +223,7 @@ public class OptScanModuleCtrlService { return result; } - public OptScanResult optScan(ProjBuildinInfo projBuildinInfo, Integer subProjIndex) throws AppException { + public OptScanResult optScan(ProjBuildInInfo projBuildinInfo, Integer subProjIndex) throws AppException { return optScan(projBuildinInfo, subProjIndex, true); } } diff --git a/src/main/java/a8k/app/service/lowerctrl/TubeFeedingCtrlService.java b/src/main/java/a8k/app/service/lowerctrl/TubeFeedingCtrlService.java index 003f24b..adef80e 100644 --- a/src/main/java/a8k/app/service/lowerctrl/TubeFeedingCtrlService.java +++ b/src/main/java/a8k/app/service/lowerctrl/TubeFeedingCtrlService.java @@ -16,66 +16,23 @@ import a8k.app.hardware.channel.A8kCanBusService; import a8k.app.hardware.type.A8kEcode; import a8k.app.hardware.type.InputIOId; import a8k.app.hardware.type.MId; +import a8k.app.type.misc.TubeHolderScanResult; +import a8k.app.type.misc.TubeScanResult; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.util.Arrays; - @Component @RequiredArgsConstructor @Slf4j public class TubeFeedingCtrlService { - - public static class TubeHolderScanResult { - public TubesScanResult[] tube = new TubesScanResult[10]; - public String tubeHolderType = ""; - public Boolean isVirtual = false; - - public String toString() { - return String.format("%s %s", tubeHolderType, Arrays.toString(tube)); - } - - public Boolean isHasTubeInIt() { - for (TubesScanResult tubesScanResult : tube) { - if (tubesScanResult.isTubeExist) { - return true; - } - } - return false; - } - } - - public static class TubesScanResult { - public Boolean isTubeExist = false; - public Boolean isHighTube = false; - public String tubeCode = null; - - public TubesScanResult() { - } - - public TubesScanResult(Boolean isTubeExist, Boolean isHighTube, String tubeCode) { - this.isTubeExist = isTubeExist; - this.isHighTube = isHighTube; - this.tubeCode = tubeCode; - } - - public String toString() { - if (isTubeExist) { - return String.format("%s(%s)", tubeCode, isHighTube ? "High" : "Low"); - } else { - return "Null"; - } - } - } - - static Integer tubeScanOvertime = 3000; - static Integer tubeHolderScanOvertime = 5000; + static Integer tubeScanOvertime = 3000; // 试管扫码超时 + static Integer tubeHolderScanOvertime = 3000; // 试管架类型扫码超时 private final AppEventBusService ebus; private final A8kCanBusService canBus; private final TubeFeedingModuleParamMgr stp; - private final CodeScanerDriver codeScaner; + private final CodeScanerDriver codeScanner; private final TubeFeedingExCtrlService tubeFeedingExCtrlService; private final MiniServoDriver miniServoDriver; private final StepMotorCtrlDriver stepMotorCtrlDriver; @@ -176,7 +133,7 @@ public class TubeFeedingCtrlService { try { tubeFeedingExCtrlService.scanClampModClamp(); miniServoDriver.miniServoRotateWithTorque(MiniServoMId.ShakeModTubeScanerRotateSV, stp.getTubeScanServoTorque()); - return codeScaner.feedingModScannerModCodeScannerScanCode(tubeScanOvertime); + return codeScanner.feedingModScannerModCodeScannerScanCode(tubeScanOvertime); } finally { miniServoDriver.moduleStop(MiniServoMId.ShakeModTubeScanerRotateSV); tubeFeedingExCtrlService.scanClampModRelease(); @@ -192,7 +149,7 @@ public class TubeFeedingCtrlService { moveTubeRackToScanPos(); tubeFeedingExCtrlService.scanClampModClamp(); - result = codeScaner.feedingModScannerModCodeScannerScanCode(tubeHolderScanOvertime); + result = codeScanner.feedingModScannerModCodeScannerScanCode(tubeHolderScanOvertime); tubeFeedingExCtrlService.scanClampModRelease(); if (result == null || result.isEmpty()) { return ""; @@ -247,43 +204,43 @@ public class TubeFeedingCtrlService { } //逐个扫描试管 - TubesScanResult[] tubesScanResult = new TubesScanResult[10]; - boolean hasTube = false; - for (int i = 0; i < tubesScanResult.length; i++) { - tubesScanResult[i] = new TubesScanResult(); + TubeScanResult[] tubeScanResult = new TubeScanResult[10]; + boolean hasTube = false; + for (int i = 0; i < tubeScanResult.length; i++) { + tubeScanResult[i] = new TubeScanResult(); Boolean isTubeExist = moveAndjudgeTubeExist(i); if (isTubeExist) { - hasTube = true; - tubesScanResult[i].isTubeExist = true; + hasTube = true; + tubeScanResult[i].isTubeExist = true; if (tubeHolderType == A8kTubeHolderType.BloodTube) { - tubesScanResult[i].isHighTube = moveAndJudgeTubeAltit(i); - tubesScanResult[i].tubeCode = moveToTubeScanPosAndScan(i); + tubeScanResult[i].isHighTube = moveAndJudgeTubeAltit(i); + tubeScanResult[i].tubeCode = moveToTubeScanPosAndScan(i); } else { - tubesScanResult[i].isHighTube = false; - tubesScanResult[i].tubeCode = ""; + tubeScanResult[i].isHighTube = false; + tubeScanResult[i].tubeCode = ""; } } else { - tubesScanResult[i].isTubeExist = false; + tubeScanResult[i].isTubeExist = false; } - log.info("扫描试管{}完成,{}", i, tubesScanResult[i]); + log.info("扫描试管{}完成,{}", i, tubeScanResult[i]); } //处理扫描结果 if (!hasTube) { log.error("试管架中没有试管"); - ebus.pushEvent(new AppWarningNotifyEvent(A8kEcode.APPE_TUBE_HOLDER_TYPE_IS_NOT_SUPPORT)); + ebus.pushEvent(new AppWarningNotifyEvent(A8kEcode.APPE_TUBEHOLDER_IS_EMPTY)); return null; } result.tubeHolderType = tubeType; - result.tube = tubesScanResult; + result.tube = tubeScanResult; return result; } - - public TubeHolderScanResult enterAndScanTubeHodler() throws AppException { + public TubeHolderScanResult enterAndScanTubeholder() throws AppException { //清空试管架 if (!tubeXChannelIsEmpty()) { + log.warn("试管架通道有试管,弹出试管架"); ejectTubeHolder(); } //入料 @@ -291,12 +248,10 @@ public class TubeFeedingCtrlService { Boolean enterSuc = enterTubeHolder(); if (!enterSuc) { log.warn("进料超时"); - // ejectTubeHolderInEnterPos(); ebus.pushEvent(new AppWarningNotifyEvent(A8kEcode.APPE_INFEED_OVERTIME_FAIL)); return null; } return scanTubeHodler(); - } // diff --git a/src/main/java/a8k/app/service/lowerctrl/TurnableMoveCtrlService.java b/src/main/java/a8k/app/service/lowerctrl/TurnableMoveCtrlService.java index a574453..526eafd 100644 --- a/src/main/java/a8k/app/service/lowerctrl/TurnableMoveCtrlService.java +++ b/src/main/java/a8k/app/service/lowerctrl/TurnableMoveCtrlService.java @@ -38,20 +38,20 @@ public class TurnableMoveCtrlService { //检查钩板电机是否处于终点位置 if (!inputDetectDriver.getIOState(InputIOId.PullerMZeroPPS)) { log.error("PullerM is not in zero pos"); - throw new AppException(A8kEcode.APPE_PULLERM_INIT_POS_ERROR); + throw new AppException(A8kEcode.APPE_PULLER_MOTOR_INIT_POS_ERROR); } //检查板夹仓光电是否处于起点位置 if (!inputDetectDriver.getIOState(InputIOId.PusherMZeroPPS)) { log.error("PusherM is not in zero pos"); - throw new AppException(A8kEcode.APPE_PUSHERM_INIT_POS_ERROR); + throw new AppException(A8kEcode.APPE_PUSHER_MOTOR_INIT_POS_ERROR); } } private void checkBeforeMovePlateBox() throws AppException { if (!inputDetectDriver.getIOState(InputIOId.PusherMZeroPPS)) { log.error("PusherM is not in zero pos "); - throw new AppException(A8kEcode.APPE_PUSHERM_INIT_POS_ERROR); + throw new AppException(A8kEcode.APPE_PUSHER_MOTOR_INIT_POS_ERROR); } } diff --git a/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java b/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java index 3b6370a..86056ab 100644 --- a/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java +++ b/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java @@ -1,9 +1,8 @@ package a8k.app.service.mainctrl; -import a8k.app.constant.AppConstant; import a8k.app.hardware.type.A8kEcode; import a8k.app.i18n.Internationalization; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.service.data.ProjInfoMgrService; import a8k.app.service.statemgr.GStateMgrService; import a8k.app.service.statemgr.ConsumablesMgrService; @@ -131,7 +130,7 @@ public class AppConsumablesScanService { return ret; } - ProjBuildinInfo projBuildinInfo = null; + ProjBuildInInfo projBuildinInfo = null; try { projBuildinInfo = projInfoMgrService.getProjBuildInInfo(projExtInfoCard.projId); } catch (AppException e) { @@ -204,7 +203,7 @@ public class AppConsumablesScanService { Assert.isTrue(result.projId != 0, "result.projId!=0"); - ProjBuildinInfo projCfg = null; + ProjBuildInInfo projCfg = null; try { projCfg = projInfoMgrService.getProjBuildInInfo(projExtInfoCard.projId); } catch (AppException e) { diff --git a/src/main/java/a8k/app/service/module/InFeedingCtrlModule.java b/src/main/java/a8k/app/service/module/InFeedingCtrlModule.java index 783190f..6078cfa 100644 --- a/src/main/java/a8k/app/service/module/InFeedingCtrlModule.java +++ b/src/main/java/a8k/app/service/module/InFeedingCtrlModule.java @@ -1,7 +1,6 @@ package a8k.app.service.module; import a8k.OS; -import a8k.app.dao.type.combination.ProjBuildinInfo; import a8k.app.dao.type.db.ReactionReport; import a8k.app.engineer.service.type.A8kCmdRunnable; import a8k.app.factory.AppErrorFactory; @@ -23,10 +22,11 @@ import a8k.app.type.a8k.A8kTubeHolderType; import a8k.app.type.a8k.BloodType; import a8k.app.type.a8k.state.TubeHolderInfo; import a8k.app.type.a8k.state.TubeInfo; +import a8k.app.type.a8k.state.enumtype.TubeHolderState; import a8k.app.type.appevent.AppWarningNotifyEvent; import a8k.app.type.error.AETubeError; -import a8k.app.type.error.AppError; import a8k.app.type.exception.AppException; +import a8k.app.type.misc.TubeHolderScanResult; import a8k.app.type.ui.TubeHolderSetting; import a8k.app.utils.ZWorkThread; import cn.hutool.core.util.ObjectUtil; @@ -110,17 +110,21 @@ public class InFeedingCtrlModule { continue; } - //入料 - if (isReady()) { - TubeHolderSetting tubeSetting = tubeHolderSettingMgrService.getThelastActiveTubeHolderSetting(); - priDoAction(tubeSetting); - tubeHolderSettingMgrService.removeLockTubeHolderSetting(tubeSetting); + //如果Tubeholder处于空的状态,则弹入新的试管架 + if (tubeStateMgr.getTubeholderState().equals(TubeHolderState.IDLE)) { + //如果入料通道光电被触发 + // 或者软件推测有新的试管架 + if (getTubeholderEnterPosPPS() || + deviceWorkStateMgrService.isMayHaveNewTubeHolder()) { + TubeHolderSetting tubeSetting = tubeHolderSettingMgrService.getThelastActiveTubeHolderSetting(); + scanTubeHolder(tubeSetting); + tubeHolderSettingMgrService.removeLockTubeHolderSetting(tubeSetting); + } } //出料 - if (tubeStateMgr.isTubeHolderInProcessing() - && tubeStateMgr.isTubeholderHasBeenProcessed() - ) { + if (!tubeStateMgr.getTubeholderState().equals(TubeHolderState.IDLE) && + tubeStateMgr.isAllTubeInTubeholderHasBeenProcessed()) { docmd("弹出试管架", () -> { tubeFeedingCtrlService.ejectTubeHolder(); tubeFeedingCtrlService.moveTubeRackMoveToEnterPos(); @@ -137,13 +141,9 @@ public class InFeedingCtrlModule { state.isWorking = false; } - - private Boolean isReady() { - if (tubeStateMgr.isTubeHolderProcessCompleted()) { - return getTubeholderEnterPosPPS() || deviceWorkStateMgrService.isMayHaveNewTubeHolder(); - } - return false; - } + //********************************************************************************************** + // PRIVATE + //********************************************************************************************** private Boolean getTubeholderEnterPosPPS() { // 入料通道是否为空 if (gStateMgrService.getDeviceRunMode().equals(DeviceRunMode.RealMode)) { @@ -158,13 +158,13 @@ public class InFeedingCtrlModule { } - A8kEcode initOneTube(TubeInfo tube, Integer i, TubeFeedingCtrlService.TubeHolderScanResult scanResult, - TubeHolderSetting setting) { + private A8kEcode initOneTube(TubeInfo tube, Integer i, TubeHolderScanResult scanResult, TubeHolderSetting setting) { if (!scanResult.tube[i].isTubeExist) { tube.isHasTube = false; return A8kEcode.SUC; } - tube.isHasTube = (scanResult.tube[i].isHighTube); + tube.isHasTube = true; + tube.isHighTube = (scanResult.tube[i].isHighTube); // 首先赋值默认值 tube.bloodType = (BloodType.WHOLE_BLOOD); @@ -174,19 +174,10 @@ public class InFeedingCtrlModule { // 然后赋值用户配置的数值 if (setting != null) { - List projBuildinInfos = null; - try { - projBuildinInfos = projInfoMgrService.getProjBuildInInfo(setting.tubeSettings[i].projId); - } catch (AppException e) { - log.error("项目信息不存在,{}", setting.tubeSettings[i].projId); - return A8kEcode.PROJ_CARD_ERROR_WRONG_UNSUPPORTED; - } - tube.bloodType = (setting.tubeSettings[i].bloodType); tube.sampleBarcode = (setting.tubeSettings[i].sampleBarcode); tube.userid = (setting.tubeSettings[i].userid); tube.projIds = (setting.tubeSettings[i].projId); - } // TODO:添加请求后台的代码 if (tube.projIds.isEmpty()) { @@ -195,11 +186,8 @@ public class InFeedingCtrlModule { return A8kEcode.SUC; } - TubeHolderInfo parseScanResult(TubeFeedingCtrlService.TubeHolderScanResult scanResult, TubeHolderSetting setting) { + private TubeHolderInfo parseScanResult(TubeHolderScanResult scanResult, TubeHolderSetting setting) { log.info("解析试管架扫描结果"); - log.info("扫描结果 {}", scanResult); - log.info("试管架配置 {}", setting); - TubeHolderInfo tubeholderInfo = new TubeHolderInfo(); // 获取试管架类型 @@ -214,6 +202,7 @@ public class InFeedingCtrlModule { for (int i = 0; i < tubeholderInfo.tubeInfos.length; i++) { A8kEcode ecode = initOneTube(tubeholderInfo.tubeInfos[i], i, scanResult, setting); if (!ecode.equals(A8kEcode.SUC)) { + log.error("解析试管架扫描结果失败,试管{}错误码:{}", i, ecode); appEventBusService.pushEvent(new AppWarningNotifyEvent(new AETubeError(ecode, i))); return null; } @@ -221,7 +210,7 @@ public class InFeedingCtrlModule { return tubeholderInfo; } - TubeFeedingCtrlService.TubeHolderScanResult doScanHolder() throws AppException { + private TubeHolderScanResult doScanHolder() throws AppException { /* * 如果使能了虚拟设备,那么直接返回虚拟设备的扫描结果 */ @@ -229,7 +218,7 @@ public class InFeedingCtrlModule { if (gStateMgrService.getDeviceRunMode().equals(DeviceRunMode.RealMode)) { return stc.scanTubeHodler(); } else if (gStateMgrService.getDeviceRunMode().equals(DeviceRunMode.RunOnlyMode)) { - TubeFeedingCtrlService.TubeHolderScanResult result = stc.scanTubeHodler(); + TubeHolderScanResult result = stc.scanTubeHodler(); ZAppChecker.check(result == null, A8kEcode.CODEERROR, "试管架中有试管,但是测试模式中设置了虚拟试管扫描结果"); return stc.takeVirtualTubeScanResult(); } else if (gStateMgrService.getDeviceRunMode().equals(DeviceRunMode.VirtualMode)) { @@ -238,25 +227,19 @@ public class InFeedingCtrlModule { return null; } - Boolean doEnterTubeHolder() throws AppException { + + private void scanTubeHolder(TubeHolderSetting tubeHolderSetting) throws AppException { log.info("推入试管架"); + Boolean enterTubeHolderSuc = false; if (gStateMgrService.getDeviceRunMode().equals(DeviceRunMode.RealMode)) { - return stc.enterTubeHolder(); + enterTubeHolderSuc = stc.enterTubeHolder(); } else if (gStateMgrService.getDeviceRunMode().equals(DeviceRunMode.RunOnlyMode)) { - stc.enterTubeHolder(); - return true; + enterTubeHolderSuc = stc.enterTubeHolder(); } else if (gStateMgrService.getDeviceRunMode().equals(DeviceRunMode.VirtualMode)) { - return true; + enterTubeHolderSuc = false; } - return false; - } - void doEjectHodler() throws AppException { - docmd("弹出试管架", stc::ejectTubeHolder); - } - - public void priDoAction(TubeHolderSetting tubeHolderSetting) throws AppException { - if (!doEnterTubeHolder()) { + if (!enterTubeHolderSuc) { if (deviceWorkStateMgrService.isMayHaveNewTubeHolder()) { deviceWorkStateMgrService.setMayHaveNewTubeHolder(false); log.warn("尝试推入试管架忽略"); @@ -270,18 +253,19 @@ public class InFeedingCtrlModule { deviceWorkStateMgrService.setMayHaveNewTubeHolder(true); // 扫描试管架 - TubeFeedingCtrlService.TubeHolderScanResult scanResult; - scanResult = doScanHolder(); + TubeHolderScanResult scanResult = doScanHolder(); if (scanResult == null) { log.error("扫描试管架失败"); - doEjectHodler(); + docmd("弹出试管架", stc::ejectTubeHolder); return; } // 解析试管架扫描结果 + log.info("扫描结果 {}", scanResult); + log.info("试管架配置 {}", tubeHolderSetting); TubeHolderInfo tubeholderInfo = parseScanResult(scanResult, tubeHolderSetting); if (tubeholderInfo == null) { - doEjectHodler(); + docmd("弹出试管架", stc::ejectTubeHolder); return; } @@ -292,11 +276,15 @@ public class InFeedingCtrlModule { if (e.getError().eq(A8kEcode.APPE_CONSUME_NOT_ENOUGH, A8kEcode.APPE_TIP_NOT_ENOUGH)) { deviceWorkStateMgrService.setConsumeNotEnoughErrorFlag(); } + log.error("添加试管架到系统中失败", e); appEventBusService.pushEvent(new AppWarningNotifyEvent(e.error)); - doEjectHodler(); + docmd("弹出试管架", stc::ejectTubeHolder); } } + //*************************************************************************************************** + // BASE UTILS // + //*************************************************************************************************** private void docmd(String mark, A8kCmdRunnable runnable, A8kCmdRunnable virtualAction) throws AppException { log.info("DO {}", mark); diff --git a/src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java b/src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java index 8096eff..9bb1c98 100644 --- a/src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java +++ b/src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java @@ -1,8 +1,6 @@ package a8k.app.service.module; import a8k.OS; -import a8k.app.dao.type.combination.ProjBuildinInfo; -import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.engineer.service.type.A8kCmdRunnable; import a8k.app.factory.AppErrorFactory; import a8k.app.service.lowerctrl.OptScanModuleCtrlService; @@ -13,10 +11,8 @@ import a8k.app.service.statemgr.IncubationPlateStateMgr; import a8k.app.service.statemgr.OptScanModuleStateMgr; import a8k.app.service.utils.UISender; import a8k.app.type.DeviceRunMode; -import a8k.app.type.a8k.ConsumableGroup; import a8k.app.type.a8k.pos.IncubatorPos; import a8k.app.type.a8k.state.IncubationSubTank; -import a8k.app.type.a8k.state.SampleInfo; import a8k.app.type.a8k.state.enumtype.IncubationSubTankState; import a8k.app.type.error.AppError; import a8k.app.type.exception.AppException; @@ -28,7 +24,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.io.Serializable; -import java.util.List; /** * diff --git a/src/main/java/a8k/app/service/module/SamplePreProcessModule.java b/src/main/java/a8k/app/service/module/SamplePreProcessModule.java index c45db13..ac84524 100644 --- a/src/main/java/a8k/app/service/module/SamplePreProcessModule.java +++ b/src/main/java/a8k/app/service/module/SamplePreProcessModule.java @@ -154,11 +154,8 @@ public class SamplePreProcessModule { // 预定孵育盘位置 for (var cxt : tube.getPreProcessContexts()) { //预定孵育盘位置 - cxt.incubatorPos = incubationPlateStateMgr.takeOneIncubationIDLEPos( - (IncubatorPos pos) -> { - incubationPlateStateMgr.syncProjInfo(pos, cxt.projBuildinInfo, cxt.projExtInfoCard); - incubationPlateStateMgr.syncSampleInfo(pos, cxt.sampleInfo); - } + cxt.incubatorPos = incubationPlateStateMgr.takeOneIncubationIDLEPos((IncubatorPos pos) -> + incubationPlateStateMgr.syncCxtInfo(pos, cxt.sampleInfo, cxt.projBuildinInfo, cxt.projExtInfoCard, cxt.consumableInfo) ); //使用耗材 consumablesMgrService.useReserveConsumable(cxt.consumableInfo); diff --git a/src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgr.java b/src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgr.java index c3035fe..e00224b 100644 --- a/src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgr.java +++ b/src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgr.java @@ -2,6 +2,7 @@ package a8k.app.service.statemgr; import a8k.app.type.DeviceRunMode; import a8k.app.type.a8k.BloodType; +import a8k.app.type.a8k.pos.ConsumableInfo; import a8k.app.type.a8k.state.IncubationPlate; import a8k.app.type.a8k.state.IncubationSubTank; import a8k.app.type.a8k.state.SampleInfo; @@ -10,7 +11,7 @@ import a8k.app.type.a8k.pos.IncubatorPos; import a8k.app.type.a8k.proj.ProjBriefInfo; import a8k.app.type.error.AppError; import a8k.app.dao.type.db.ProjExtInfoCard; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.service.utils.ProjInfoUtils; import a8k.app.utils.ZTimeUtils; import cn.hutool.core.util.ObjectUtil; @@ -74,7 +75,7 @@ public class IncubationPlateStateMgr { synchronized public Boolean isHasEnoughIncubationIDLEPos(Integer num) { var subtanks = incubationPlate.subtanks; - int count = 0; + int count = 0; for (IncubationSubTank subtank : subtanks) { if (subtank.state.equals(IncubationSubTankState.EMPTY) && subtank.getHasCleared()) { count++; @@ -181,9 +182,6 @@ public class IncubationPlateStateMgr { } - - - synchronized public void setIncubationToErrorState(IncubatorPos pos, List errors) { if (pos == null) { return; @@ -206,25 +204,43 @@ public class IncubationPlateStateMgr { } } - synchronized public void syncSampleInfo(IncubatorPos pos, SampleInfo sampleInfo) { + // synchronized public void syncSampleInfo(IncubatorPos pos,) { + // var subtanks = incubationPlate.subtanks; + // subtanks[pos.off].sampleId = sampleInfo.sampleId; + // subtanks[pos.off].bloodType = sampleInfo.bloodType; + // subtanks[pos.off].sampleBarcode = sampleInfo.sampleBarcode; + // subtanks[pos.off].userid = sampleInfo.userid; + // subtanks[pos.off].isEmergency = sampleInfo.isEmergency; + // } + // + // synchronized public void syncProjInfo(IncubatorPos pos, ProjBuildInInfo projBuildinInfo, ProjExtInfoCard projExtInfoCard) { + // var subtanks = incubationPlate.subtanks; + // subtanks[pos.off].projBuildinInfo = projBuildinInfo; + // subtanks[pos.off].projExtInfoCard = projExtInfoCard; + // subtanks[pos.off].lotId = projExtInfoCard.lotId; + // subtanks[pos.off].projId = projBuildinInfo.projId; + // subtanks[pos.off].projInfo = ProjInfoUtils.buildProjBrefInfo(projBuildinInfo); + // } + + synchronized public void syncCxtInfo(IncubatorPos pos, SampleInfo sampleInfo, ProjBuildInInfo projBuildinInfo, ProjExtInfoCard projExtInfoCard, ConsumableInfo consumableInfo) { var subtanks = incubationPlate.subtanks; + subtanks[pos.off].sampleId = sampleInfo.sampleId; subtanks[pos.off].bloodType = sampleInfo.bloodType; subtanks[pos.off].sampleBarcode = sampleInfo.sampleBarcode; subtanks[pos.off].userid = sampleInfo.userid; subtanks[pos.off].isEmergency = sampleInfo.isEmergency; - } - synchronized public void syncProjInfo(IncubatorPos pos, ProjBuildinInfo projBuildinInfo, ProjExtInfoCard projExtInfoCard) { - var subtanks = incubationPlate.subtanks; subtanks[pos.off].projBuildinInfo = projBuildinInfo; subtanks[pos.off].projExtInfoCard = projExtInfoCard; subtanks[pos.off].lotId = projExtInfoCard.lotId; subtanks[pos.off].projId = projBuildinInfo.projId; subtanks[pos.off].projInfo = ProjInfoUtils.buildProjBrefInfo(projBuildinInfo); + subtanks[pos.off].consumableInfo = consumableInfo; } + synchronized public void setIncubationToWaitingForDropState(IncubatorPos pos) { var subtanks = incubationPlate.subtanks; subtanks[pos.off].state = IncubationSubTankState.WAITING_FOR_DROP; diff --git a/src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java b/src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java index 6f8df6b..883900d 100644 --- a/src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java +++ b/src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java @@ -8,7 +8,7 @@ import a8k.app.type.a8k.state.enumtype.OptScanModuleStateEnum; import a8k.app.type.a8k.proj.ProjBriefInfo; import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.service.data.UtilsProjectColorAllocer; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import cn.hutool.core.util.ObjectUtil; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -78,7 +78,7 @@ public class OptScanModuleStateMgr { log.info("光学模块:状态->反应板准备就绪 {}", sampleInfo); } - synchronized public void syncProjInfo(ProjBuildinInfo projBuildinInfo, ProjExtInfoCard projExtInfoCard) { + synchronized public void syncProjInfo(ProjBuildInInfo projBuildinInfo, ProjExtInfoCard projExtInfoCard) { optScanModule.setProjBuildinInfo(projBuildinInfo); optScanModule.setProjExtInfoCard(projExtInfoCard); optScanModule.setLotId(projExtInfoCard.lotId); diff --git a/src/main/java/a8k/app/service/statemgr/TubeStateMgr.java b/src/main/java/a8k/app/service/statemgr/TubeStateMgr.java index 6995ed6..a06c816 100644 --- a/src/main/java/a8k/app/service/statemgr/TubeStateMgr.java +++ b/src/main/java/a8k/app/service/statemgr/TubeStateMgr.java @@ -20,12 +20,11 @@ import a8k.app.type.error.AppError; import a8k.app.type.exception.AppException; import a8k.app.type.a8k.BloodType; import a8k.app.service.data.UtilsProjectColorAllocer; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.service.utils.ProjInfoUtils; import a8k.app.service.utils.ZAppChecker; import a8k.app.utils.ZJsonHelper; import cn.hutool.core.util.ObjectUtil; -import jakarta.annotation.Resource; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -118,7 +117,7 @@ public class TubeStateMgr { private ProjectPreProcessContext newProjectPreProcessContext(Tube tube, Integer projId, Integer off) throws AppException { SampleInfo sampleInfo = tube.getSampleInfo(); - ProjBuildinInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(projId); + ProjBuildInInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(projId); ConsumableInfo consumableInfo = consumablesMgrService.reserveConsumable(projBuildinInfo.reactionFlowType, projId); ProjExtInfoCard projExtInfoCard = projInfoMgrService.getProjExtInfoCard(consumableInfo.lotid); @@ -183,8 +182,8 @@ public class TubeStateMgr { tube.setUserid(tubeInfo.userid); tube.setState(TubeState.TO_BE_PROCESSED); tube.setProjIds(new ArrayList<>(tubeInfo.projIds)); - tube.setProjBuildinInfos(projInfoMgrService.getProjBuildInInfo(tubeInfo.projIds)); - tube.setProjInfo(ProjInfoUtils.buidProjBriefInfoList(tube.getProjBuildinInfos())); + tube.setProjBuildInInfos(projInfoMgrService.getProjBuildInInfo(tubeInfo.projIds)); + tube.setProjInfo(ProjInfoUtils.buidProjBriefInfoList(tube.getProjBuildInInfos())); String sampleId = newSample(tube); tube.setSampleId(sampleId); @@ -222,7 +221,7 @@ public class TubeStateMgr { synchronized public void commitEmergencySampleSetting(String userid, String sampleBarcode, BloodType bloodType,// List projIds, Boolean isVirtual) throws AppException { Tube tube = emergencyTubePos.tube; - List projBuildInInfos = new ArrayList<>(); + List projBuildInInfos = new ArrayList<>(); if (projIds.isEmpty()) { throw new AppException(A8kEcode.APPE_A8K_PROJ_ID_IS_EMPTY); } @@ -265,7 +264,7 @@ public class TubeStateMgr { tube.setIsEmergency(true); tube.setProjInfo(ProjInfoUtils.buidProjBriefInfoList(projBuildInInfos)); tube.setProjIds(projIds); - tube.setProjBuildinInfos(projBuildInInfos); + tube.setProjBuildInInfos(projBuildInInfos); //!! 这行代码后续代码需要保证无异常发生 Integer off = 0; for (Integer projId : projIds) { @@ -429,11 +428,11 @@ public class TubeStateMgr { return nextTubeIndex; } - - synchronized public Boolean isTubeHolderProcessCompleted() { - return tubeHolder.getState().equals(TubeHolderState.IDLE); + synchronized public TubeHolderState getTubeholderState() { + return tubeHolder.getState(); } + synchronized public Boolean isHasSomeToBeProcessedTube() { for (Tube tube : tubeHolder.getTubes()) { if (tube.getState().equals(TubeState.TO_BE_PROCESSED)) { @@ -443,23 +442,19 @@ public class TubeStateMgr { return emergencyTubePos.tube.getState().equals(TubeState.TO_BE_PROCESSED); } - synchronized public Boolean isTubeholderHasBeenProcessed() { + /** + * 检查试管架中所有试管是否都已经被处理完成 + * @return 如果所有试管都已经被处理完成,则返回true,否则返回false + */ + synchronized public Boolean isAllTubeInTubeholderHasBeenProcessed() { for (Tube tube : tubeHolder.getTubes()) { - if ((!tube.getState().equals(TubeState.EMPTY) && - !tube.getState().equals(TubeState.PROCESS_COMPLETE) && - !tube.getState().equals(TubeState.ERROR) - )) { + if(tube.getState().isNotEq(TubeState.EMPTY, TubeState.PROCESS_COMPLETE, TubeState.ERROR)) { return false; } } return true; } - synchronized public Boolean isTubeHolderInProcessing() { - return !tubeHolder.getState().equals(TubeHolderState.IDLE); - } - - synchronized public Boolean isHasEmergencyTubeToBeProcessed() { return emergencyTubePos.tube.getState().equals(TubeState.TO_BE_PROCESSED); } diff --git a/src/main/java/a8k/app/service/utils/ProjInfoReader.java b/src/main/java/a8k/app/service/utils/ProjInfoReader.java index a5b110e..9467d5c 100644 --- a/src/main/java/a8k/app/service/utils/ProjInfoReader.java +++ b/src/main/java/a8k/app/service/utils/ProjInfoReader.java @@ -1,14 +1,14 @@ package a8k.app.service.utils; import a8k.app.type.a8k.BloodType; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.dao.type.db.ProjExtInfoCard; import lombok.extern.slf4j.Slf4j; @Slf4j public class ProjInfoReader { - static public Integer getSampleVol(ProjBuildinInfo buildinInfo, ProjExtInfoCard extInfoCard, BloodType bloodType) { + static public Integer getSampleVol(ProjBuildInInfo buildinInfo, ProjExtInfoCard extInfoCard, BloodType bloodType) { if (bloodType.equals(BloodType.WHOLE_BLOOD)) { if (isEffectiveValue(extInfoCard.wBloodSampleVolUl)) { diff --git a/src/main/java/a8k/app/service/utils/ProjInfoUtils.java b/src/main/java/a8k/app/service/utils/ProjInfoUtils.java index d99e6da..7033241 100644 --- a/src/main/java/a8k/app/service/utils/ProjInfoUtils.java +++ b/src/main/java/a8k/app/service/utils/ProjInfoUtils.java @@ -1,6 +1,6 @@ package a8k.app.service.utils; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.type.a8k.proj.ProjBriefInfo; @@ -9,7 +9,7 @@ import java.util.List; public class ProjInfoUtils { - static public ProjBriefInfo buildProjBrefInfo(ProjBuildinInfo buildinInfo) { + static public ProjBriefInfo buildProjBrefInfo(ProjBuildInInfo buildinInfo) { ProjBriefInfo projBriefInfo = new ProjBriefInfo(); projBriefInfo.projId = buildinInfo.projId; projBriefInfo.projName = buildinInfo.projName; @@ -18,9 +18,9 @@ public class ProjInfoUtils { return projBriefInfo; } - static public List buidProjBriefInfoList(List projBuildinInfos) { + static public List buidProjBriefInfoList(List projBuildInInfos) { List projBriefInfos = new ArrayList<>(); - for (ProjBuildinInfo projBuildinInfo : projBuildinInfos) { + for (ProjBuildInInfo projBuildinInfo : projBuildInInfos) { ProjBriefInfo projBriefInfo = buildProjBrefInfo(projBuildinInfo); projBriefInfos.add(projBriefInfo); } diff --git a/src/main/java/a8k/app/teststate/TestStateMgrService.java b/src/main/java/a8k/app/teststate/TestStateMgrService.java index e28dcf9..ca00ec5 100644 --- a/src/main/java/a8k/app/teststate/TestStateMgrService.java +++ b/src/main/java/a8k/app/teststate/TestStateMgrService.java @@ -4,6 +4,7 @@ package a8k.app.teststate; import a8k.app.service.lowerctrl.ConsumablesScanCtrlService; import a8k.app.service.lowerctrl.TubeFeedingCtrlService; import a8k.app.service.utils.ReactionPlate2DCodeHelper; +import a8k.app.type.misc.TubeHolderScanResult; import jakarta.annotation.Resource; import org.springframework.stereotype.Component; @@ -18,7 +19,7 @@ public class TestStateMgrService { * 插入虚拟的试管架扫描结果 * @param scanResult 试管架扫描结果 */ - public void insertVirtualBloodTubeHolder(TubeFeedingCtrlService.TubeHolderScanResult scanResult) { + public void insertVirtualBloodTubeHolder(TubeHolderScanResult scanResult) { tubeFeedingCtrlService.setVirtualTubeScanResult(scanResult); } diff --git a/src/main/java/a8k/app/type/a8k/proj/ProjInfo.java b/src/main/java/a8k/app/type/a8k/proj/ProjInfo.java index 262a7ef..4b34a6d 100644 --- a/src/main/java/a8k/app/type/a8k/proj/ProjInfo.java +++ b/src/main/java/a8k/app/type/a8k/proj/ProjInfo.java @@ -1,15 +1,15 @@ package a8k.app.type.a8k.proj; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.dao.type.db.ProjExtInfoCard; import java.io.Serializable; public class ProjInfo implements Serializable { - public ProjBuildinInfo buildIn; + public ProjBuildInInfo buildIn; public ProjExtInfoCard ext; - public ProjInfo(ProjBuildinInfo buildIn, ProjExtInfoCard ext) { + public ProjInfo(ProjBuildInInfo buildIn, ProjExtInfoCard ext) { this.buildIn = buildIn; this.ext = ext; } diff --git a/src/main/java/a8k/app/type/a8k/state/IncubationSubTank.java b/src/main/java/a8k/app/type/a8k/state/IncubationSubTank.java index 22ee2fb..7013da9 100644 --- a/src/main/java/a8k/app/type/a8k/state/IncubationSubTank.java +++ b/src/main/java/a8k/app/type/a8k/state/IncubationSubTank.java @@ -1,6 +1,5 @@ package a8k.app.type.a8k.state; -import a8k.app.service.statemgr.ConsumablesMgrService; import a8k.app.type.a8k.pos.ConsumableInfo; import a8k.app.type.a8k.state.enumtype.IncubationSubTankState; import a8k.app.type.a8k.pos.IncubatorPos; @@ -8,7 +7,7 @@ import a8k.app.type.error.AppError; import a8k.app.type.a8k.BloodType; import a8k.app.type.a8k.proj.ProjBriefInfo; import a8k.app.dao.type.db.ProjExtInfoCard; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; @@ -42,7 +41,7 @@ public class IncubationSubTank implements Serializable { public ProjExtInfoCard projExtInfoCard = null; @JsonIgnore - public ProjBuildinInfo projBuildinInfo = null; + public ProjBuildInInfo projBuildinInfo = null; public String lotId = ""; //批次号 diff --git a/src/main/java/a8k/app/type/a8k/state/OptScanModuleState.java b/src/main/java/a8k/app/type/a8k/state/OptScanModuleState.java index 8ce6542..4fe2d10 100644 --- a/src/main/java/a8k/app/type/a8k/state/OptScanModuleState.java +++ b/src/main/java/a8k/app/type/a8k/state/OptScanModuleState.java @@ -5,7 +5,7 @@ import a8k.app.type.a8k.state.enumtype.OptScanModuleStateEnum; import a8k.app.type.a8k.BloodType; import a8k.app.type.a8k.proj.ProjBriefInfo; import a8k.app.dao.type.db.ProjExtInfoCard; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -39,7 +39,7 @@ public class OptScanModuleState implements Serializable { @JsonIgnore ProjExtInfoCard projExtInfoCard; @JsonIgnore - ProjBuildinInfo projBuildinInfo; + ProjBuildInInfo projBuildinInfo; Boolean cleared = false; //是否被清空过 diff --git a/src/main/java/a8k/app/type/a8k/state/ProjectPreProcessContext.java b/src/main/java/a8k/app/type/a8k/state/ProjectPreProcessContext.java index 1604cf9..b4799c4 100644 --- a/src/main/java/a8k/app/type/a8k/state/ProjectPreProcessContext.java +++ b/src/main/java/a8k/app/type/a8k/state/ProjectPreProcessContext.java @@ -1,19 +1,20 @@ package a8k.app.type.a8k.state; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.dao.type.db.ProjExtInfoCard; -import a8k.app.service.statemgr.ConsumablesMgrService; import a8k.app.type.a8k.pos.ConsumableInfo; import a8k.app.type.a8k.pos.IncubatorPos; import com.fasterxml.jackson.annotation.JsonIgnore; -public class ProjectPreProcessContext { +import java.io.Serializable; + +public class ProjectPreProcessContext implements Serializable { public String cxtId = ""; public SampleInfo sampleInfo = null; public ConsumableInfo consumableInfo = null; //耗材信息 public Integer projId = 0; //项目ID @JsonIgnore - public ProjBuildinInfo projBuildinInfo; + public ProjBuildInInfo projBuildinInfo; @JsonIgnore public ProjExtInfoCard projExtInfoCard; public IncubatorPos incubatorPos = null; //孵育盘位置 @@ -21,7 +22,7 @@ public class ProjectPreProcessContext { public ProjectPreProcessContext(SampleInfo sampleInfo, ConsumableInfo consumableInfo, Integer projId, - ProjBuildinInfo projBuildinInfo, + ProjBuildInInfo projBuildinInfo, ProjExtInfoCard projExtInfoCard, Integer off) { this.cxtId = String.format("{}-{}-{}", sampleInfo.sampleId, projId, off); this.sampleInfo = sampleInfo; diff --git a/src/main/java/a8k/app/type/a8k/state/Tube.java b/src/main/java/a8k/app/type/a8k/state/Tube.java index 063f295..04d1b8f 100644 --- a/src/main/java/a8k/app/type/a8k/state/Tube.java +++ b/src/main/java/a8k/app/type/a8k/state/Tube.java @@ -5,7 +5,7 @@ import a8k.app.type.a8k.state.enumtype.TubeState; import a8k.app.type.error.AppError; import a8k.app.type.a8k.BloodType; import a8k.app.type.a8k.proj.ProjBriefInfo; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -45,12 +45,10 @@ public class Tube implements Serializable { List errors = new ArrayList<>(); //错误信息 List preProcessContexts = new ArrayList<>(); //预处理上下文 - @JsonIgnore A8kTubeHolderType tubeHolderType = null; - @JsonIgnore - List projBuildinInfos = new ArrayList<>(); + List projBuildInInfos = new ArrayList<>(); public Tube(Integer pos) { this.pos = pos; diff --git a/src/main/java/a8k/app/type/a8k/state/TubeInfo.java b/src/main/java/a8k/app/type/a8k/state/TubeInfo.java index 4b43fbd..9d822da 100644 --- a/src/main/java/a8k/app/type/a8k/state/TubeInfo.java +++ b/src/main/java/a8k/app/type/a8k/state/TubeInfo.java @@ -1,14 +1,6 @@ package a8k.app.type.a8k.state; -import a8k.app.dao.type.combination.ProjBuildinInfo; -import a8k.app.type.a8k.A8kTubeHolderType; import a8k.app.type.a8k.BloodType; -import a8k.app.type.a8k.proj.ProjBriefInfo; -import a8k.app.type.a8k.state.enumtype.TubeState; -import a8k.app.type.error.AppError; -import com.fasterxml.jackson.annotation.JsonIgnore; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; import java.io.Serializable; import java.util.ArrayList; diff --git a/src/main/java/a8k/app/type/a8k/state/enumtype/TubeState.java b/src/main/java/a8k/app/type/a8k/state/enumtype/TubeState.java index 9659ece..68733af 100644 --- a/src/main/java/a8k/app/type/a8k/state/enumtype/TubeState.java +++ b/src/main/java/a8k/app/type/a8k/state/enumtype/TubeState.java @@ -12,8 +12,7 @@ public enum TubeState { ; - - public Boolean isEq(TubeState ... states) { + public Boolean isEq(TubeState... states) { for (TubeState state : states) { if (this.equals(state)) { return true; @@ -21,4 +20,13 @@ public enum TubeState { } return false; } + + public Boolean isNotEq(TubeState... states) { + for (TubeState state : states) { + if (this.equals(state)) { + return false; + } + } + return true; + } } diff --git a/src/main/java/a8k/app/type/misc/TubeHolderScanResult.java b/src/main/java/a8k/app/type/misc/TubeHolderScanResult.java new file mode 100644 index 0000000..ecb06b3 --- /dev/null +++ b/src/main/java/a8k/app/type/misc/TubeHolderScanResult.java @@ -0,0 +1,22 @@ +package a8k.app.type.misc; + +import java.util.Arrays; + +public class TubeHolderScanResult { + public TubeScanResult[] tube = new TubeScanResult[10]; + public String tubeHolderType = ""; + public Boolean isVirtual = false; + + public String toString() { + return String.format("%s %s", tubeHolderType, Arrays.toString(tube)); + } + + public Boolean isHasTubeInIt() { + for (TubeScanResult tubeScanResult : tube) { + if (tubeScanResult.isTubeExist) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/a8k/app/type/misc/TubeScanResult.java b/src/main/java/a8k/app/type/misc/TubeScanResult.java new file mode 100644 index 0000000..abaa6f3 --- /dev/null +++ b/src/main/java/a8k/app/type/misc/TubeScanResult.java @@ -0,0 +1,24 @@ +package a8k.app.type.misc; + +public class TubeScanResult { + public Boolean isTubeExist = false; + public Boolean isHighTube = false; + public String tubeCode = null; + + public TubeScanResult() { + } + + public TubeScanResult(Boolean isTubeExist, Boolean isHighTube, String tubeCode) { + this.isTubeExist = isTubeExist; + this.isHighTube = isHighTube; + this.tubeCode = tubeCode; + } + + public String toString() { + if (isTubeExist) { + return String.format("Has(Code:%s IsH:%s)", tubeCode, isHighTube ? "High" : "Low"); + } else { + return "None"; + } + } +} diff --git a/src/main/java/a8k/extui/factory/ProjExtInfoCardFactory.java b/src/main/java/a8k/extui/factory/ProjExtInfoCardFactory.java index 0887327..2886660 100644 --- a/src/main/java/a8k/extui/factory/ProjExtInfoCardFactory.java +++ b/src/main/java/a8k/extui/factory/ProjExtInfoCardFactory.java @@ -7,7 +7,7 @@ import a8k.app.type.a8k.optfn.A8kNormalFn; import a8k.app.type.a8k.optfn.A8kPiecewiseFn; import a8k.app.type.a8k.optfn.A8kFnType; import a8k.app.service.data.ProjInfoMgrService; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import java.util.Date; @@ -18,7 +18,7 @@ public class ProjExtInfoCardFactory { ProjInfoMgrService projInfoMgrService = SpringBootBeanUtil.getBean(ProjInfoMgrService.class); - ProjBuildinInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(projId); + ProjBuildInInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(projId); if (lotId == null || lotId.isEmpty()) { lotId = String.format("%s000000", projBuildinInfo.projShortName); diff --git a/src/main/java/a8k/extui/page/debug/P01ProjInfoDebugPage.java b/src/main/java/a8k/extui/page/debug/P01ProjInfoDebugPage.java index 6fd0eb4..ed84cf7 100644 --- a/src/main/java/a8k/extui/page/debug/P01ProjInfoDebugPage.java +++ b/src/main/java/a8k/extui/page/debug/P01ProjInfoDebugPage.java @@ -7,7 +7,7 @@ import a8k.extui.factory.ProjExtInfoCardFactory; import a8k.app.service.data.ProjIdCardInfoMgrService; import a8k.app.service.data.ProjInfoMgrService; import a8k.app.service.statemgr.GStateMgrService; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.utils.ZDateUtils; import a8k.extui.mgr.ExtApiPageMgr; import a8k.extui.type.ExtApiStatu; @@ -49,8 +49,8 @@ public class P01ProjInfoDebugPage { } public String addAllProjFakeProjInfoCard() throws AppException { - List projBuildinInfos = projInfoMgrService.getAllProjBuildInInfo(); - for (ProjBuildinInfo projBuildinInfo : projBuildinInfos) { + List projBuildInInfos = projInfoMgrService.getAllProjBuildInInfo(); + for (ProjBuildInInfo projBuildinInfo : projBuildInInfos) { ProjExtInfoCard projExtInfoCard = ProjExtInfoCardFactory.buildProjExtInfoCard(projBuildinInfo.projId, null); projIdCardInfoMgrService.saveProjExtInfoCard(projExtInfoCard); } diff --git a/src/main/java/a8k/extui/page/extapp/A8kOptVerification.java b/src/main/java/a8k/extui/page/extapp/A8kOptVerification.java index 3964381..e7a5e19 100644 --- a/src/main/java/a8k/extui/page/extapp/A8kOptVerification.java +++ b/src/main/java/a8k/extui/page/extapp/A8kOptVerification.java @@ -23,7 +23,7 @@ import a8k.app.type.a8k.opt.A8kOptType; import a8k.app.type.a8k.ConsumableGroup; import a8k.app.type.a8k.pos.IncubatorPos; import a8k.app.type.exception.AppException; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import org.springframework.stereotype.Component; @@ -127,7 +127,7 @@ public class A8kOptVerification { public A8kOptType optType; public A8kScanCurve optScanCurve; public OptScanResult optScanResult; - public ProjBuildinInfo projInfo; + public ProjBuildInInfo projInfo; public Integer subProjIndex; } @@ -142,7 +142,7 @@ public class A8kOptVerification { return null; } - public void generateOptReport(ProjBuildinInfo info, Integer subProjIndex, OptScanResult optScanResult) + public void generateOptReport(ProjBuildInInfo info, Integer subProjIndex, OptScanResult optScanResult) throws IOException { OptScanReport report = new OptScanReport(); report.optScanCurve = A8kScanCurveFactory.createScanCurve1200Point(optScanResult.rawData.rawData); diff --git a/src/main/java/a8k/extui/page/extapp/OptModuleParamCalibration.java b/src/main/java/a8k/extui/page/extapp/OptModuleParamCalibration.java index f8cb0d4..67686d7 100644 --- a/src/main/java/a8k/extui/page/extapp/OptModuleParamCalibration.java +++ b/src/main/java/a8k/extui/page/extapp/OptModuleParamCalibration.java @@ -1,6 +1,6 @@ package a8k.extui.page.extapp; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.optalgo.type.A8kOptPeakInfo; import a8k.app.service.data.ProjInfoMgrService; import a8k.app.type.a8k.ConsumableGroup; @@ -180,7 +180,7 @@ public class OptModuleParamCalibration { A8kScanCurve optScanCurve = null; public A8kOptPeakInfo doOptScan(Integer projId, Integer subProjIndex) throws AppException { - ProjBuildinInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(projId); + ProjBuildInInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(projId); var result = optScanModuleCtrlService.optScan(projBuildinInfo, subProjIndex); optScanCurve = A8kScanCurveFactory.createScanCurve1200Point(result.rawData.rawData); return result.analysResult; diff --git a/src/main/java/a8k/extui/page/extapp/UsrOperationSimulationPage.java b/src/main/java/a8k/extui/page/extapp/UsrOperationSimulationPage.java index d442c77..c85927b 100644 --- a/src/main/java/a8k/extui/page/extapp/UsrOperationSimulationPage.java +++ b/src/main/java/a8k/extui/page/extapp/UsrOperationSimulationPage.java @@ -1,10 +1,11 @@ package a8k.extui.page.extapp; -import a8k.app.service.lowerctrl.TubeFeedingCtrlService; import a8k.app.type.a8k.A8kTubeHolderType; import a8k.app.type.a8k.ConsumableGroup; import a8k.app.type.exception.AppException; import a8k.app.dao.type.db.ProjExtInfoCard; +import a8k.app.type.misc.TubeHolderScanResult; +import a8k.app.type.misc.TubeScanResult; import a8k.extui.factory.ProjExtInfoCardFactory; import a8k.app.service.data.ProjIdCardInfoMgrService; import a8k.app.service.data.ProjInfoMgrService; @@ -66,18 +67,18 @@ public class UsrOperationSimulationPage { public void putInVirtualBloodTubeHolder() throws AppException { gstate.checkIfIsInVirtualModeOrRunOnlyMode(); - TubeFeedingCtrlService.TubeHolderScanResult scanResult = new TubeFeedingCtrlService.TubeHolderScanResult(); + TubeHolderScanResult scanResult = new TubeHolderScanResult(); scanResult.tubeHolderType = A8kTubeHolderType.BloodTube.scanCode; - scanResult.tube[0] = new TubeFeedingCtrlService.TubesScanResult(true, true, ""); - scanResult.tube[1] = new TubeFeedingCtrlService.TubesScanResult(true, true, ""); - scanResult.tube[2] = new TubeFeedingCtrlService.TubesScanResult(true, true, ""); - scanResult.tube[3] = new TubeFeedingCtrlService.TubesScanResult(true, true, ""); - scanResult.tube[4] = new TubeFeedingCtrlService.TubesScanResult(true, true, ""); - scanResult.tube[5] = new TubeFeedingCtrlService.TubesScanResult(true, true, ""); - scanResult.tube[6] = new TubeFeedingCtrlService.TubesScanResult(true, true, ""); - scanResult.tube[7] = new TubeFeedingCtrlService.TubesScanResult(true, true, ""); - scanResult.tube[8] = new TubeFeedingCtrlService.TubesScanResult(true, true, ""); - scanResult.tube[9] = new TubeFeedingCtrlService.TubesScanResult(true, true, ""); + scanResult.tube[0] = new TubeScanResult(true, true, ""); + scanResult.tube[1] = new TubeScanResult(true, true, ""); + scanResult.tube[2] = new TubeScanResult(true, true, ""); + scanResult.tube[3] = new TubeScanResult(true, true, ""); + scanResult.tube[4] = new TubeScanResult(true, true, ""); + scanResult.tube[5] = new TubeScanResult(true, true, ""); + scanResult.tube[6] = new TubeScanResult(true, true, ""); + scanResult.tube[7] = new TubeScanResult(true, true, ""); + scanResult.tube[8] = new TubeScanResult(true, true, ""); + scanResult.tube[9] = new TubeScanResult(true, true, ""); testStateMgrService.insertVirtualBloodTubeHolder(scanResult); } diff --git a/src/main/java/a8k/extui/page/extapp/debug_assistant/IDCardDataGeneratorPage.java b/src/main/java/a8k/extui/page/extapp/debug_assistant/IDCardDataGeneratorPage.java index 39cd68c..86372b7 100644 --- a/src/main/java/a8k/extui/page/extapp/debug_assistant/IDCardDataGeneratorPage.java +++ b/src/main/java/a8k/extui/page/extapp/debug_assistant/IDCardDataGeneratorPage.java @@ -6,7 +6,7 @@ import a8k.extui.factory.ProjExtInfoCardFactory; import a8k.app.service.data.ProjIdCardInfoMgrService; import a8k.app.service.data.ProjInfoMgrService; import a8k.app.service.statemgr.GStateMgrService; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.extui.mgr.ExtApiPageMgr; import a8k.extui.type.ExtApiStatu; import jakarta.annotation.PostConstruct; @@ -44,8 +44,8 @@ public class IDCardDataGeneratorPage { } public String addAllProjFakeProjInfoCard() throws AppException { - List projBuildinInfos = projInfoMgrService.getAllProjBuildInInfo(); - for (ProjBuildinInfo projBuildinInfo : projBuildinInfos) { + List projBuildInInfos = projInfoMgrService.getAllProjBuildInInfo(); + for (ProjBuildInInfo projBuildinInfo : projBuildInInfos) { ProjExtInfoCard projExtInfoCard = ProjExtInfoCardFactory.buildProjExtInfoCard(projBuildinInfo.projId, null); projIdCardInfoMgrService.saveProjExtInfoCard(projExtInfoCard); } diff --git a/src/main/java/a8k/extui/page/extsetting/db/ProjInfoMgrPage.java b/src/main/java/a8k/extui/page/extsetting/db/ProjInfoMgrPage.java index 55b43e0..318f610 100644 --- a/src/main/java/a8k/extui/page/extsetting/db/ProjInfoMgrPage.java +++ b/src/main/java/a8k/extui/page/extsetting/db/ProjInfoMgrPage.java @@ -5,7 +5,7 @@ import a8k.app.controler.filemgr.StorageControler; import a8k.app.dao.ProjectBaseInfoDao; import a8k.app.service.data.ProjIdCardInfoMgrService; import a8k.app.service.data.ProjInfoMgrService; -import a8k.app.dao.type.combination.ProjBuildinInfo; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.extui.mgr.ExtApiPageMgr; import a8k.extui.type.ExtUIPageCfg; import a8k.extui.type.ExtUiTable; @@ -49,11 +49,11 @@ public class ProjInfoMgrPage { public ExtUiTable getProjInfoBreifList() throws AppException { var allproj = projInfoMgrService.getAllProjBuildInInfo(); - return new ExtUiTable(ProjBuildinInfo.class, allproj); + return new ExtUiTable(ProjBuildInInfo.class, allproj); } - public ProjBuildinInfo getProjInfoById(Integer projId) throws AppException { + public ProjBuildInInfo getProjInfoById(Integer projId) throws AppException { return projInfoMgrService.getProjBuildInInfo(projId); } diff --git a/src/main/java/a8k/extui/page/test/verification/P30InfeedAndPreProcessPosVerificationPage.java b/src/main/java/a8k/extui/page/test/verification/P30InfeedAndPreProcessPosVerificationPage.java index f0076b9..24ee454 100644 --- a/src/main/java/a8k/extui/page/test/verification/P30InfeedAndPreProcessPosVerificationPage.java +++ b/src/main/java/a8k/extui/page/test/verification/P30InfeedAndPreProcessPosVerificationPage.java @@ -2,6 +2,7 @@ package a8k.extui.page.test.verification; import a8k.app.type.exception.AppException; import a8k.app.service.lowerctrl.*; +import a8k.app.type.misc.TubeHolderScanResult; import a8k.extui.mgr.ExtApiPageMgr; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; @@ -21,7 +22,7 @@ public class P30InfeedAndPreProcessPosVerificationPage { } //移动到试管架存在检测位置 - public String moveAndjudgeTubeExist(Integer tubeIndex) throws AppException { + public String moveAndJudgeTubeExist(Integer tubeIndex) throws AppException { boolean exit = tubeFeedingCtrlService.moveAndjudgeTubeExist(tubeIndex - 1); return exit ? "存在" : "不存在"; } @@ -32,13 +33,11 @@ public class P30InfeedAndPreProcessPosVerificationPage { } public String moveToTubeScanPosAndScan(Integer tubeIndex) throws AppException { - String code = tubeFeedingCtrlService.moveToTubeScanPosAndScan(tubeIndex - 1); - return code; + return tubeFeedingCtrlService.moveToTubeScanPosAndScan(tubeIndex - 1); } public String moveToTubeRackScanPosAndScan() throws AppException { - var code = tubeFeedingCtrlService.moveToTubeRackScanPosAndScan(); - return code; + return tubeFeedingCtrlService.moveToTubeRackScanPosAndScan(); } @@ -47,8 +46,8 @@ public class P30InfeedAndPreProcessPosVerificationPage { * @return 管架扫描结果 * @throws AppException ae */ - public TubeFeedingCtrlService.TubeHolderScanResult scanTubeHolder() throws AppException { - TubeFeedingCtrlService.TubeHolderScanResult result = tubeFeedingCtrlService.enterAndScanTubeHodler(); + public TubeHolderScanResult scanTubeHolder() throws AppException { + TubeHolderScanResult result = tubeFeedingCtrlService.enterAndScanTubeholder(); tubeFeedingCtrlService.ejectTubeHolder(); return result; } @@ -114,7 +113,7 @@ public class P30InfeedAndPreProcessPosVerificationPage { page.newGroup("入料操作"); page.addFunction("入料", this::enterTubeHolder); page.addFunction("移动到[试管]扫描位置,并扫描", this::moveToTubeScanPosAndScan).setParamVal("tubeIndex",()-> 1); - page.addFunction("移动到[试管]存在检测位置,并判断", this::moveAndjudgeTubeExist).setParamVal("tubeIndex", ()->1); + page.addFunction("移动到[试管]存在检测位置,并判断", this::moveAndJudgeTubeExist).setParamVal("tubeIndex", ()->1); page.addFunction("移动到[试管]高低检测位置,并判断", this::moveAndJudgeTubeAltit).setParamVal("tubeIndex", ()->1); page.addFunction("移动到[试管]预处理位置", this::moveTubeToPreProcessPos).setParamVal("tubeIndex",()-> 1); page.addFunction("移动到[试管架]扫描位置,并扫描", this::moveToTubeRackScanPosAndScan); diff --git a/src/main/java/a8k/extui/page/test/verification/P50VerificationScriptPage.java b/src/main/java/a8k/extui/page/test/verification/P50VerificationScriptPage.java index cbc8519..2381f7d 100644 --- a/src/main/java/a8k/extui/page/test/verification/P50VerificationScriptPage.java +++ b/src/main/java/a8k/extui/page/test/verification/P50VerificationScriptPage.java @@ -11,6 +11,7 @@ import a8k.app.hardware.driver.*; import a8k.app.service.lowerctrl.TubeFeedingCtrlService; import a8k.app.service.lowerctrl.TubePreProcessModuleExCtrlService; import a8k.app.service.lowerctrl.*; +import a8k.app.type.misc.TubeHolderScanResult; import a8k.extui.mgr.ExtApiPageMgr; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; @@ -26,7 +27,7 @@ public class P50VerificationScriptPage { @Resource TubePreProcessModuleExCtrlService tubePreProcessModuleExCtrlService; - TubeFeedingCtrlService.TubeHolderScanResult tubeHolderScanResult; + TubeHolderScanResult tubeHolderScanResult; @Resource @@ -51,7 +52,7 @@ public class P50VerificationScriptPage { throw AppException.ofAECodeError("入料失败"); } - tubeHolderScanResult = tubeFeedingCtrlService.enterAndScanTubeHodler(); + tubeHolderScanResult = tubeFeedingCtrlService.enterAndScanTubeholder(); if (tubeHolderScanResult == null) { tubeFeedingCtrlService.ejectTubeHolder(); throw AppException.ofAECodeError("扫描试管架失败");