diff --git a/sh/mkexe.bat b/sh/mkexe.bat index 28e0c0a..3d62c85 100644 --- a/sh/mkexe.bat +++ b/sh/mkexe.bat @@ -27,6 +27,8 @@ if %errorlevel% neq 0 ( mkdir dist\A8000_VIRTUAL_BAK_END\appresource\ xcopy appresource dist\A8000_VIRTUAL_BAK_END\appresource\ /s /e +start explorer dist\ + if %errorlevel% neq 0 ( echo 执行发生错误,退出脚本 diff --git a/src/main/java/a8k/BoditechA800Application.java b/src/main/java/a8k/BoditechA800Application.java index 8ed0f0c..3a5a20b 100644 --- a/src/main/java/a8k/BoditechA800Application.java +++ b/src/main/java/a8k/BoditechA800Application.java @@ -1,6 +1,7 @@ package a8k; +import a8k.app.type.DeviceRunMode; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; @@ -13,25 +14,26 @@ import org.springframework.core.env.Environment; @SpringBootApplication public class BoditechA800Application implements ApplicationListener { - @Resource - private Environment env; + @Resource + private Environment env; - public static void main(String[] args) { - SpringApplication.run(BoditechA800Application.class, args); + public static void main(String[] args) { + SpringApplication.run(BoditechA800Application.class, args); - } + } - @Override - public void onApplicationEvent(ContextRefreshedEvent event) { -// if (null == event.getApplicationContext().getParent()) { -// log.info("Springboot加载完成"); -// try { -// Runtime.getRuntime().exec(String.format("cmd /c start http://127.0.0.1:%s/exui/index.html", env.getProperty("server.port"))); -// } catch (Exception e) { -// } -// } - - - } + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + DeviceRunMode runmode = env.getProperty("device.runmode", DeviceRunMode.class); + if (runmode.equals(DeviceRunMode.VirtualMode)) { + if (null == event.getApplicationContext().getParent()) { + log.info("Springboot加载完成"); + try { + Runtime.getRuntime().exec(String.format("cmd /c start http://127.0.0.1:%s/exui/index.html", env.getProperty("server.port"))); + } catch (Exception ignored) { + } + } + } + } } diff --git a/src/main/java/a8k/app/controler/api/v1/app/data/A8kProjectInfoControler.java b/src/main/java/a8k/app/controler/api/v1/app/data/A8kProjectInfoControler.java index 52fdd9a..6d95d5e 100644 --- a/src/main/java/a8k/app/controler/api/v1/app/data/A8kProjectInfoControler.java +++ b/src/main/java/a8k/app/controler/api/v1/app/data/A8kProjectInfoControler.java @@ -1,7 +1,9 @@ package a8k.app.controler.api.v1.app.data; import a8k.app.dao.ProjectBaseInfoDao; +import a8k.app.dao.type.combination.ProjBuildInInfo; import a8k.app.dao.type.db.ProjectBaseInfo; +import a8k.app.service.data.ProjInfoMgrService; import a8k.app.type.exception.AppException; import a8k.app.type.ui.ApiRet; import io.swagger.v3.oas.annotations.Operation; @@ -23,12 +25,12 @@ import java.util.List; public class A8kProjectInfoControler { @Resource - ProjectBaseInfoDao projectBaseInfoDao; + ProjInfoMgrService projInfoMgrService; @Operation(summary = "读取设备支持的所有项目") @PostMapping("/getAll") - public ApiRet> getAll() throws AppException { - return ApiRet.success(projectBaseInfoDao.getAll()); + public ApiRet> getAll() throws AppException { + return ApiRet.success(projInfoMgrService.getAllProjBuildInInfo()); } } diff --git a/src/main/java/a8k/app/controler/api/v1/app/state/EmergencyTubeController.java b/src/main/java/a8k/app/controler/api/v1/app/state/EmergencyTubeController.java index eacdfab..7b726df 100644 --- a/src/main/java/a8k/app/controler/api/v1/app/state/EmergencyTubeController.java +++ b/src/main/java/a8k/app/controler/api/v1/app/state/EmergencyTubeController.java @@ -53,7 +53,7 @@ public class EmergencyTubeController { setting.getUserid(), setting.getSampleBarcode(), setting.getBloodType(), - setting.getProjIds(), false + setting.getProjIds() ); return ApiRet.success(); } diff --git a/src/main/java/a8k/app/controler/api/v1/app/state/TubeHolderSettingMgrController.java b/src/main/java/a8k/app/controler/api/v1/app/state/TubeHolderSettingMgrController.java index e678fe5..ae1c8df 100644 --- a/src/main/java/a8k/app/controler/api/v1/app/state/TubeHolderSettingMgrController.java +++ b/src/main/java/a8k/app/controler/api/v1/app/state/TubeHolderSettingMgrController.java @@ -1,5 +1,6 @@ package a8k.app.controler.api.v1.app.state; +import a8k.app.i18n.Internationalization; import a8k.app.type.a8k.BloodType; import a8k.app.service.mainctrl.TubeHolderSettingMgrService; import a8k.app.service.statemgr.GStateMgrService; @@ -57,14 +58,14 @@ public class TubeHolderSettingMgrController { } -// @Operation(summary = "配置试管(Muti)") -// @PostMapping("/updateMutiTubeSettings") -// public ApiRet updateTubeSetting(@RequestBody List model) throws AppException { -// for (TubeSettingVal val : model) { -// tubeSettingMgrService.updateTubeSetting(val.uuid, val.setting); -// } -// return ApiRet.success(); -// } + // @Operation(summary = "配置试管(Muti)") + // @PostMapping("/updateMutiTubeSettings") + // public ApiRet updateTubeSetting(@RequestBody List model) throws AppException { + // for (TubeSettingVal val : model) { + // tubeSettingMgrService.updateTubeSetting(val.uuid, val.setting); + // } + // return ApiRet.success(); + // } //添加试管架,返回整个列表 @Operation(summary = "添加<试管架>配置") @@ -103,8 +104,9 @@ public class TubeHolderSettingMgrController { @PostMapping("/getBloodTypes") public ApiRet> getBloodTypes() { List ret = new java.util.ArrayList<>(); - ret.add(new EnumVal().key(BloodType.WHOLE_BLOOD.name(), "全血")); - ret.add(new EnumVal().key(BloodType.SERUM_OR_PLASMA.name(), "血清/血浆")); + for (BloodType type : BloodType.values()) { + ret.add(new EnumVal().key(type.name(), Internationalization.BloodTypeToString(type))); + } return ApiRet.success(ret); } diff --git a/src/main/java/a8k/app/dao/type/combination/ProjBuildInInfo.java b/src/main/java/a8k/app/dao/type/combination/ProjBuildInInfo.java index 6bf5c06..c20335a 100644 --- a/src/main/java/a8k/app/dao/type/combination/ProjBuildInInfo.java +++ b/src/main/java/a8k/app/dao/type/combination/ProjBuildInInfo.java @@ -2,6 +2,7 @@ package a8k.app.dao.type.combination; import a8k.app.dao.type.db.OptCfg; import a8k.app.dao.type.db.ProjectBaseInfo; +import a8k.app.type.a8k.BloodType; import a8k.app.type.a8k.opt.A8kOptType; import a8k.app.type.a8k.proj.A8kReactionFlowType; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -32,8 +33,10 @@ public class ProjBuildInInfo implements Serializable { public A8kReactionFlowType reactionFlowType; //反应流程 /*样本配置*/ - public Integer wBloodSampleVolUl; //全血样本量ul - public Integer serumSampleVolUl; //血清/血浆样本量ul + public Integer defaultSampleVolUl; //默认样本量ul + public Integer wBloodSampleVolUl; //全血样本量ul + public Integer serumSampleVolUl; //血清/血浆样本量ul + public Integer fecesSampleVolUl; //粪便样本量ul public Integer shakeTimes; //摇匀次数 /*缓冲液配置*/ @@ -42,11 +45,14 @@ public class ProjBuildInInfo implements Serializable { /*缓和液预处理配置*/ public Integer mixedLiquidMixingTimes; //混合液混匀次数 public Integer mixedLiquidMixingVolUl; //混合液混匀量ul + public Integer mixedLiquidPreReactionTimeMin; //反应板预反应时间Min /*孵育配置*/ public Integer reactionPlateIncubationTimeMin; //反应板孵育时间Min public Integer reactionPlateDropletVolUl; //反应板滴样量ul + public List supportBloodTypes; //支持的血液类型 + public List optcfg; public ProjBuildInInfo() {} //for json diff --git a/src/main/java/a8k/app/dao/type/db/ProjectBaseInfo.java b/src/main/java/a8k/app/dao/type/db/ProjectBaseInfo.java index b6ea3b2..b513022 100644 --- a/src/main/java/a8k/app/dao/type/db/ProjectBaseInfo.java +++ b/src/main/java/a8k/app/dao/type/db/ProjectBaseInfo.java @@ -1,10 +1,21 @@ package a8k.app.dao.type.db; +import a8k.app.type.a8k.BloodType; import a8k.app.type.a8k.proj.A8kReactionFlowType; import a8k.app.utils.ZJsonHelper; import java.io.Serializable; - +import java.util.List; + +/** + * + * 项目基础信息 + * + * 修改这个类之后,要同步修改 + * 1. zapp_a8k_proj_info.csv + * 2. ProjBuildInInfo (字段要保持和ProjectBaseInfo同名,这样ProjBuildInInfo会自动被赋值) + * + */ public class ProjectBaseInfo implements Serializable { public int id; @@ -21,8 +32,10 @@ public class ProjectBaseInfo implements Serializable { public A8kReactionFlowType reactionFlowType; //反应流程 /*样本配置*/ + public Integer defaultSampleVolUl; //默认样本量ul public Integer wBloodSampleVolUl; //全血样本量ul public Integer serumSampleVolUl; //血清/血浆样本量ul + public Integer fecesSampleVolUl; //粪便样本量ul public Integer shakeTimes; //摇匀次数 /*缓冲液配置*/ @@ -31,11 +44,12 @@ public class ProjectBaseInfo implements Serializable { /*缓和液预处理配置*/ public Integer mixedLiquidMixingTimes; //混合液混匀次数 public Integer mixedLiquidMixingVolUl; //混合液混匀量ul + public Integer mixedLiquidPreReactionTimeMin; //反应板预反应时间Min /*孵育配置*/ public Integer reactionPlateIncubationTimeMin; //反应板孵育时间Min public Integer reactionPlateDropletVolUl; //反应板滴样量ul - + public List supportBloodTypes; //支持的血液类型 public String toString() { return ZJsonHelper.objectToJson(this); } diff --git a/src/main/java/a8k/app/i18n/Internationalization.java b/src/main/java/a8k/app/i18n/Internationalization.java index f85a2f4..ed5d821 100644 --- a/src/main/java/a8k/app/i18n/Internationalization.java +++ b/src/main/java/a8k/app/i18n/Internationalization.java @@ -1,5 +1,6 @@ package a8k.app.i18n; +import a8k.app.type.a8k.BloodType; import a8k.app.type.error.ConsumablesScanReportErrorType; import a8k.app.hardware.type.A8kEcode; @@ -108,6 +109,15 @@ public class Internationalization { case REACTION_PLATE_2D_CODE_FORMATE_ERROR -> "反应板二维码格式错误"; case CODE_ERROR_PROJINFO_IS_ERROR -> "代码错误,项目信息异常"; case UN_SUPPORT_PROJ -> "不支持的项目"; + case PROJ_ONLY_NEED_REACTION_PLATE -> "当前项目只需要反应板"; + }; + } + + public static String BloodTypeToString(BloodType bloodType) { + return switch (bloodType) { + case WHOLE_BLOOD -> "全血"; + case SERUM_OR_PLASMA -> "血清/血浆"; + case FECES -> "粪便"; }; } } diff --git a/src/main/java/a8k/app/optalgo/A8kPeakAnalyzer.java b/src/main/java/a8k/app/optalgo/A8kPeakAnalyzer.java index 5100d5b..d5964a1 100644 --- a/src/main/java/a8k/app/optalgo/A8kPeakAnalyzer.java +++ b/src/main/java/a8k/app/optalgo/A8kPeakAnalyzer.java @@ -295,15 +295,19 @@ public class A8kPeakAnalyzer { ProjExtInfoCard.A8kOptFnGroup fnFormual = ProjInfoUtils.getA8kOptFnFormula(optcxt.projInfoCxt.ext, optcxt.subProjIndex); Assert.isTrue(fnFormual != null, "fnFormual must not be null"); Double result1 = null; + // + //粪便类型的样本使用,血清和血浆的参数 + //ref:https://iflytop1.feishu.cn/wiki/AuDiwywvViKc8tkbGB7cJQBwnig?fromScene=spaceOverview + // if (fnFormual.fnType.equals(A8kFnType.NormalFn)) { result1 = switch (optcxt.sampleInfo.bloodType) { case WHOLE_BLOOD -> callNorFn(optcxt, fnFormual.bloodNorFn, a8kOptPeakInfo); - case SERUM_OR_PLASMA -> callNorFn(optcxt, fnFormual.serumNorFn, a8kOptPeakInfo); + case SERUM_OR_PLASMA, FECES -> callNorFn(optcxt, fnFormual.serumNorFn, a8kOptPeakInfo); }; } else if (fnFormual.fnType.equals(A8kFnType.PiecewiseFn)) { result1 = switch (optcxt.sampleInfo.bloodType) { case WHOLE_BLOOD -> callPiecewiseFn(optcxt, fnFormual.bloodPiecewiseFn, a8kOptPeakInfo); - case SERUM_OR_PLASMA -> callPiecewiseFn(optcxt, fnFormual.serumPiecewiseFn, a8kOptPeakInfo); + case SERUM_OR_PLASMA, FECES -> callPiecewiseFn(optcxt, fnFormual.serumPiecewiseFn, a8kOptPeakInfo); }; } diff --git a/src/main/java/a8k/app/service/analyzer/ConsumableStateAnalyzerService.java b/src/main/java/a8k/app/service/analyzer/ConsumableStateAnalyzerService.java index 38d22d1..5f0072b 100644 --- a/src/main/java/a8k/app/service/analyzer/ConsumableStateAnalyzerService.java +++ b/src/main/java/a8k/app/service/analyzer/ConsumableStateAnalyzerService.java @@ -2,6 +2,7 @@ package a8k.app.service.analyzer; import a8k.SpringBootBeanUtil; import a8k.app.service.statemgr.ConsumablesMgrService; +import a8k.app.type.a8k.proj.A8kReactionFlowType; import a8k.app.type.a8k.state.TubeHolderInfo; import a8k.app.type.a8k.state.TubeInfo; import a8k.app.type.exception.AppException; @@ -131,7 +132,7 @@ public class ConsumableStateAnalyzerService { public Boolean isHasEnoughTip(List projs) { int tipNeed = 0; - tipNeed = projs.size() * 3;//每个项目假设需要3个tip + tipNeed = projs.size() * A8kReactionFlowType.getSupportTipPrepareNumEachProject();//每个项目假设需要3个tip return consumablesMgrService.isHasEnoughTips(tipNeed); } @@ -140,7 +141,7 @@ public class ConsumableStateAnalyzerService { for (TubeInfo tube : tubeHolder.tubeInfos) { tipNeed += tube.projIds.size(); } - tipNeed = tipNeed * 3;//每个项目假设需要3个tip + tipNeed = tipNeed * A8kReactionFlowType.getSupportTipPrepareNumEachProject();//每个项目假设需要3个tip return consumablesMgrService.isHasEnoughTips(tipNeed); } diff --git a/src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java b/src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java index 018adb3..9c4b1a7 100644 --- a/src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java +++ b/src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java @@ -4,6 +4,7 @@ import a8k.app.constant.GearBacklashConstant; import a8k.app.hardware.driver.PipetteCtrlDriverV2; import a8k.app.service.param.hbotpos.*; import a8k.app.type.a8k.ConsumableGroup; +import a8k.app.type.a8k.pos.PreReactionPos; import a8k.app.type.a8k.pos.TipGroupPos; import a8k.app.type.a8k.Pos2d; import a8k.app.type.a8k.Pos3d; @@ -22,12 +23,12 @@ import org.springframework.stereotype.Component; public class HbotMoveExCtrlService { - private final HbotFixedPosParamMgr hbotFixedPosParamMgr; - private final HbotSamplePosParamMgr hbotSamplePosParamMgr; - private final HbotTipPosMgr hbotTipPosMgr; - private final Hbot2DCodeScanParamMgr hbot2DCodeScanParamMgr; - private final HbotLittleBSPosMgr hbotLittleBSPosMgr; - private final HbotLargeBottleBSPosMgr hbotLargeBottleBSPosMgr; + private final HbotFixedPosParamMgr hbotFixedPosParamMgr; + private final HbotSamplePosParamMgr hbotSamplePosParamMgr; + private final HbotTipPosMgr hbotTipPosMgr; + private final Hbot2DCodeScanParamMgr hbot2DCodeScanParamMgr; + private final HbotLittleBSPosMgr hbotLittleBSPosMgr; + private final HbotLargeBottleBSPosMgr hbotLargeBottleBSPosMgr; private final PipetteCtrlDriverV2 pipetteCtrlDriver; private final HbotMoveCtrlService hbotMoveCtrlService; @@ -96,15 +97,25 @@ public class HbotMoveExCtrlService { hbotMoveCtrlService.hbotMoveTo(hbotFixedPosParamMgr.getDropLiquidPos()); } + public void moveToDropLiquidPosXY() throws AppException { + moveToXY(hbotFixedPosParamMgr.getDropLiquidPos()); + } public void moveTo(Pos3d pos) throws AppException { hbotMoveCtrlService.hbotMoveTo(pos); } public void moveToXY(Pos3d pos) throws AppException { - Pos3d poscpy = new Pos3d(pos); - poscpy.z = 0; - hbotMoveCtrlService.hbotMoveTo(poscpy); + Pos3d posCpy = new Pos3d(pos); + posCpy.z = 0; + hbotMoveCtrlService.hbotMoveTo(posCpy); + } + + public void moveToPreReactionPosXY(PreReactionPos preReactionPos) throws AppException { + switch (preReactionPos.type) { + case ProbeSubstance -> moveToXY(hbotLittleBSPosMgr.getProbeSubstanceContainerPos(preReactionPos.group, preReactionPos.index)); + case BufferSolution -> moveToXY(hbotLittleBSPosMgr.getLittleBSContainerPos(preReactionPos.group, preReactionPos.index)); + } } diff --git a/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java b/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java index f64866b..d43a373 100644 --- a/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java +++ b/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java @@ -35,19 +35,19 @@ public class LiquidOperationCtrService { /* * CTRL-SERVICE */ - private final HbotMoveExCtrlService hbotMoveExCtrlService; - private final PipetteCtrlDriverV2 pipetteCtrlDriverV2; + private final HbotMoveExCtrlService hbotMoveExCtrlService; + private final PipetteCtrlDriverV2 pipetteCtrlDriverV2; /* * PARAM-MGR */ - private final HbotLittleBSPosMgr hbotLittleBSPosMgr; - private final HbotLargeBottleBSPosMgr hbotLargeBottleBSPosMgr; + private final HbotLittleBSPosMgr hbotLittleBSPosMgr; + private final HbotLargeBottleBSPosMgr hbotLargeBottleBSPosMgr; /** * StateMgr */ - private final HbotSamplePosParamMgr hbotSamplePosParamMgr; - private final HbotFixedPosParamMgr hbotFixedPosParamMgr; - private final TipOperationCtrlModule tipOperationCtrlModule; + private final HbotSamplePosParamMgr hbotSamplePosParamMgr; + private final HbotFixedPosParamMgr hbotFixedPosParamMgr; + private final TipOperationCtrlModule tipOperationCtrlModule; ProjBuildInInfo projBuildinInfo; @@ -138,13 +138,34 @@ public class LiquidOperationCtrService { }; } + + public void pirceLittleBuffer(PreReactionPos pos) throws AppException { + // 取TIP + tipOperationCtrlModule.tryTakeTip(); + ZAppChecker.check(pipetteCtrlDriverV2.readTipState(), A8kEcode.CODEERROR, "未检测到TIP"); + + Pos3d pircePos; + ContainerCpyId containerCpyId; + + if (pos.type.equals(LittleBottleConsumableType.ProbeSubstance)) { + pircePos = hbotLittleBSPosMgr.getProbeSubstancePiercePos(pos.group, pos.index); + containerCpyId = ContainerCpyId.DetectSubstancesCup; + } else { + pircePos = hbotLittleBSPosMgr.getLittleBSPiercePos(pos.group, pos.index); + containerCpyId = ContainerCpyId.LittleBufferCup; + } + hbotMoveExCtrlService.moveToXY(pircePos); + pipetteCtrlDriverV2.pierceThroughBlock(containerCpyId, pircePos.z); + } + + /** * 取样本 * @param from 样本位置 * @param ul 吸取量 * @throws AppException 异常 */ - public void takeSampleOnly(A8kSamplePos from, Integer ul) throws AppException { + public void takeSample(A8kSamplePos from, Integer ul) throws AppException { log.info("takeSampleOnly: from={},ul={}ul", from, ul); Pos3d sampleContainerPos = hbotSamplePosParamMgr.getSampleContainerPos(from);//样本位置 @@ -177,37 +198,7 @@ public class LiquidOperationCtrService { } - public void pirceLittleBuffer(PreReactionPos pos) throws AppException { - // 取TIP - tipOperationCtrlModule.tryTakeTip(); - ZAppChecker.check(pipetteCtrlDriverV2.readTipState(), A8kEcode.CODEERROR, "未检测到TIP"); - - Pos3d pircePos; - ContainerCpyId containerCpyId; - - if (pos.type.equals(LittleBottleConsumableType.ProbeSubstance)) { - pircePos = hbotLittleBSPosMgr.getProbeSubstancePiercePos(pos.group, pos.index); - containerCpyId = ContainerCpyId.DetectSubstancesCup; - } else { - pircePos = hbotLittleBSPosMgr.getLittleBSPiercePos(pos.group, pos.index); - containerCpyId = ContainerCpyId.LittleBufferCup; - } - hbotMoveExCtrlService.moveToXY(pircePos); - pipetteCtrlDriverV2.pierceThroughBlock(containerCpyId, pircePos.z); - } - - - /** - * 取样本到探测物质 - * @param from 样本位置 - * @param pos 预先反应位置P - * @param ul 吸取量 - * @throws AppException 异常 - */ - public void takeSampleToPreReactionPos(A8kSamplePos from, PreReactionPos pos, Integer ul) throws AppException { - log.info("takeSampleToPreReactionPos: from={}, pos={}, ul={}ul", from, pos, ul); - takeSampleOnly(from, ul); - + public void distributeSampleToPreReactionPos(PreReactionPos pos, boolean reposition, boolean zmAutoMoveToZero) throws AppException { Pos3d reactionPos; ContainerCpyId containerCpyId; Integer shakeUl = MIX_VOLUME_UL; @@ -239,79 +230,18 @@ public class LiquidOperationCtrService { DistribuType.SURFACE_DIST, shakeUl * 10, // 预先反应位置的液体量 shakeTimes, - true + zmAutoMoveToZero )); } - // /** - // * 取样本液到预反应位,混合后,再取样 - // * @param from - // * @param pos - // * @param ul - // * @throws AppException - // */ - // public void takeSampleToPreReactionPosAndAspirate(A8kSamplePos from, PreReactionPos pos, Integer ul) throws AppException { - // log.info("takeSampleToPreReactionPosAndTakeToReactionPlate: from={}, pos={}, ul={}ul", from, pos, ul); - // takeSampleOnly(from, ul); - // - // Pos3d reactionPos; - // ContainerCpyId containerCpyId; - // Integer shakeUl = MIX_VOLUME_UL; - // Integer shakeTimes = 5; - // - // if (pos.type.equals(ConsumableType.ProbeSubstance)) { - // reactionPos = hbotLittleBSPosMgr.getProbeSubstanceContainerPos(pos.group, pos.index); - // containerCpyId = ContainerCpyId.DetectSubstancesCup; - // } else { - // reactionPos = hbotLittleBSPosMgr.getLittleBSContainerPos(pos.group, pos.index); - // containerCpyId = ContainerCpyId.LittleBufferCup; - // } - // if (projBuildinInfo != null) { - // shakeUl = projBuildinInfo.mixedLiquidMixingVolUl; - // shakeTimes = projBuildinInfo.mixedLiquidMixingTimes; - // } - // - // // 移动到反应位 - // UISender.txInfoMsg(log, "移动到预先反应位置:%s", reactionPos); - // hbotMoveExCtrlService.moveToXY(reactionPos); - // - // //z轴移动到反应位 - // UISender.txInfoMsg(log, "分配样本"); - // pipetteCtrlDriverV2.distributeAllBlock(new DistribuAllParam( - // reactionPos.z, - // containerCpyId, - // LiquidConfigCpyIdx.Default, - // false, - // DistribuType.SURFACE_DIST, - // shakeUl * 10, // 预先反应位置的液体量 - // shakeTimes, - // false - // )); - // - // UISender.txInfoMsg(log, "取混合液"); - // pipetteCtrlDriverV2.aspirateBlock(new AspirationParam( - // 750, // 预先反应位置的液体量 - // reactionPos.z, - // containerCpyId, - // LiquidConfigCpyIdx.Default, - // 0, - // 0, - // 0, - // 0, - // 0, - // 0, - // 0, - // 0 - // )); - // } - /** - * 取反应液到反应板上 - * @param pos 反应板位置 + * 取预先反应液体到反应位置 + * @param pos 预先反应位置 + * @param reposition 是否重新定位到预先反应位置 * @throws AppException 异常 */ - public void takePreReactionLiquid(PreReactionPos pos) throws AppException { + public void takePreReactionLiquid(PreReactionPos pos, boolean reposition) throws AppException { log.info("takePreReactionLiquidToReactionPos: from pos={}", pos); tipOperationCtrlModule.tryTakeTip(); @@ -327,8 +257,12 @@ public class LiquidOperationCtrService { containerCpyId = ContainerCpyId.LittleBufferCup; } + UISender.txInfoMsg(log, "移动到预先反应位置:%s", reactionPos); - hbotMoveExCtrlService.moveToXY(reactionPos); + + if (reposition) { + hbotMoveExCtrlService.moveToXY(reactionPos); + } UISender.txInfoMsg(log, "取混合液"); pipetteCtrlDriverV2.aspirateBlock(new AspirationParam( @@ -345,8 +279,6 @@ public class LiquidOperationCtrService { 0, 0 )); - - } public void dropLiquidToReactionPlate() throws AppException { @@ -372,4 +304,70 @@ public class LiquidOperationCtrService { } + // /** + // * 取样本到探测物质 + // * @param from 样本位置 + // * @param pos 预先反应位置P + // * @param ul 吸取量 + // * @throws AppException 异常 + // */ + // public void takeSampleToPreReactionPos(A8kSamplePos from, PreReactionPos pos, Integer ul, boolean takeMixLiquidFinal) throws AppException { + // log.info("takeSampleToPreReactionPos: from={}, pos={}, ul={}ul", from, pos, ul); + // takeSampleOnly(from, ul); + // + // Pos3d reactionPos; + // ContainerCpyId containerCpyId; + // Integer shakeUl = MIX_VOLUME_UL; + // Integer shakeTimes = 5; + // + // if (pos.type.equals(LittleBottleConsumableType.ProbeSubstance)) { + // reactionPos = hbotLittleBSPosMgr.getProbeSubstanceContainerPos(pos.group, pos.index); + // containerCpyId = ContainerCpyId.DetectSubstancesCup; + // } else { + // reactionPos = hbotLittleBSPosMgr.getLittleBSContainerPos(pos.group, pos.index); + // containerCpyId = ContainerCpyId.LittleBufferCup; + // } + // if (projBuildinInfo != null) { + // shakeUl = projBuildinInfo.mixedLiquidMixingVolUl; + // shakeTimes = projBuildinInfo.mixedLiquidMixingTimes; + // } + // + // // 移动到反应位 + // UISender.txInfoMsg(log, "移动到预先反应位置:%s", reactionPos); + // hbotMoveExCtrlService.moveToXY(reactionPos); + // + // //z轴移动到反应位 + // UISender.txInfoMsg(log, "分配样本"); + // pipetteCtrlDriverV2.distributeAllBlock(new DistribuAllParam( + // reactionPos.z, + // containerCpyId, + // LiquidConfigCpyIdx.Default, + // false, + // DistribuType.SURFACE_DIST, + // shakeUl * 10, // 预先反应位置的液体量 + // shakeTimes, + // !takeMixLiquidFinal + // )); + // + // + // if (takeMixLiquidFinal) { + // UISender.txInfoMsg(log, "取混合液"); + // pipetteCtrlDriverV2.aspirateBlock(new AspirationParam( + // 750, // 预先反应位置的液体量 + // reactionPos.z, + // containerCpyId, + // LiquidConfigCpyIdx.Default, + // 0, + // 0, + // 0, + // 0, + // 0, + // 0, + // 0, + // 0 + // )); + // } + // } + + } diff --git a/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java b/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java index aa2772e..8e53b4a 100644 --- a/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java +++ b/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java @@ -11,7 +11,6 @@ import a8k.app.service.lowerctrl.ConsumablesScanCtrlService; import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.service.statemgr.PreReactionStateMgr; import a8k.app.service.utils.ReactionPlate2DCodeHelper; -import a8k.app.type.a8k.ConsumableGroup; import a8k.app.type.a8k.LittleBottleConsumableType; import a8k.app.type.a8k.ReactionPlate2DCode; import a8k.app.type.a8k.container.*; @@ -149,43 +148,63 @@ public class AppConsumablesScanService { Integer projId = projExtInfoCard.projId; A8kReactionFlowType reactionType = projBuildinInfo.reactionFlowType; - if (reactionType.equals(A8kReactionFlowType.SampleAndBS)) { - //校验小瓶缓冲液,小瓶缓冲液+样本 - if (ZStringUtils.isNullOrEmpty(rawResult.littBSScanResult)) { - ret.state = ConsumablesScanReportErrorType.MISS_LITTSB; - ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state); - return ret; - } + switch (reactionType) { + case SampleAndBS -> { + { + //校验小瓶缓冲液,小瓶缓冲液+样本 + if (ZStringUtils.isNullOrEmpty(rawResult.littBSScanResult)) { + ret.state = ConsumablesScanReportErrorType.MISS_LITTSB; + ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state); - if (!rawResult.littBSScanResult.equals(rp2dcode.lotId)) { - ret.state = ConsumablesScanReportErrorType.LITTSB_LOTID_MISMATCH; - ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state); + return ret; + } - return ret; - } + if (!rawResult.littBSScanResult.equals(rp2dcode.lotId)) { + ret.state = ConsumablesScanReportErrorType.LITTSB_LOTID_MISMATCH; + ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state); - } else if (reactionType.equals(A8kReactionFlowType.SampleAndBSAndProbeSubstance)) { - // 校验大瓶缓冲液,大瓶缓冲液+小瓶缓冲液+样本 - if (ZStringUtils.isNullOrEmpty(rawResult.larBSScanResult)) { - ret.state = ConsumablesScanReportErrorType.MISS_LARBS; - ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state); + return ret; + } - return ret; + } } - - if (!rawResult.larBSScanResult.equals(rp2dcode.lotId)) { - ret.state = ConsumablesScanReportErrorType.LARBS_LOTID_MISMATCH; - ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state); - - return ret; + case SampleAndBSAndProbeSubstance -> { + // 校验大瓶缓冲液,大瓶缓冲液+小瓶缓冲液+样本 + if (ZStringUtils.isNullOrEmpty(rawResult.larBSScanResult)) { + ret.state = ConsumablesScanReportErrorType.MISS_LARBS; + ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state); + return ret; + } + + if (!rawResult.larBSScanResult.equals(rp2dcode.lotId)) { + ret.state = ConsumablesScanReportErrorType.LARBS_LOTID_MISMATCH; + ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state); + + return ret; + } } - - } else { - throw new RuntimeException("未知的反应流程类型"); + case SampleOnly -> { + //仅样本反应 + //只需要反应即可 + if (!ZStringUtils.isNullOrEmpty(rawResult.larBSScanResult)) { + ret.state = ConsumablesScanReportErrorType.PROJ_ONLY_NEED_REACTION_PLATE; + ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state); + log.warn("仅样本反应,扫描到大瓶缓冲液:{}", rawResult.larBSScanResult); + return ret; + } + + if (!ZStringUtils.isNullOrEmpty(rawResult.littBSScanResult)) { + ret.state = ConsumablesScanReportErrorType.PROJ_ONLY_NEED_REACTION_PLATE; + ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state); + log.warn("仅样本反应,扫描到小瓶缓冲液:{}", rawResult.littBSScanResult); + return ret; + } + } } + ret.lotId = rp2dcode.lotId; ret.projId = projId; ret.state = ConsumablesScanReportErrorType.PASS; diff --git a/src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java b/src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java index 9bb1c98..20eef36 100644 --- a/src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java +++ b/src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java @@ -77,7 +77,7 @@ public class IncubationPlateCtrlModule { private ZWorkThread workThread; - private State state = new State(); + private State state = new State(); @PostConstruct @@ -122,6 +122,7 @@ public class IncubationPlateCtrlModule { docmd("拉取反应板到滴定位", () -> turnableMoveCtrlService.trunableMoveToDropLiquidPos(incubatorPos)); dropLiquidAction.run(); + UISender.txInfoMsg(log, "开始孵育"); incubationPlateStateMgr.startIncubating(incubatorPos, System.currentTimeMillis(), incubatedTimeSec); } catch (Exception e) { state.setFatalAppError(AppErrorFactory.exceptionToAppError(e)); diff --git a/src/main/java/a8k/app/service/module/SamplePreProcessModule.java b/src/main/java/a8k/app/service/module/SamplePreProcessModule.java index 911214d..103b30a 100644 --- a/src/main/java/a8k/app/service/module/SamplePreProcessModule.java +++ b/src/main/java/a8k/app/service/module/SamplePreProcessModule.java @@ -1,10 +1,10 @@ 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; -import a8k.app.service.analyzer.A8kEcodeAnalyzer; import a8k.app.service.ctrlmodule.TipOperationCtrlModule; import a8k.app.service.lowerctrl.*; import a8k.app.type.BoolCondition; @@ -12,6 +12,7 @@ import a8k.app.service.module.bean.SamplePreProcessModuleState; import a8k.app.service.statemgr.*; import a8k.app.service.utils.UISender; import a8k.app.type.DeviceRunMode; +import a8k.app.type.PreReactionGrid; import a8k.app.type.a8k.A8kTubeHolderType; import a8k.app.type.a8k.pos.IncubatorPos; import a8k.app.type.a8k.pos.LargeBufferPos; @@ -39,6 +40,8 @@ import java.util.List; @Slf4j @RequiredArgsConstructor public class SamplePreProcessModule { + private final HbotMoveExCtrlService hbotMoveExCtrlService; + static public class TubePosInfo { public Boolean isEmergency; public Integer tubeIndex; @@ -61,6 +64,7 @@ public class SamplePreProcessModule { private final TubeFeedingCtrlService tubeFeedingCtrlService; private final ConsumablesMgrService consumablesMgrService; private final IncubationPlateCtrlModule incubationPlateCtrlModule; + private final PreReactionStateMgr preReactionStateMgr; ActionTaskPool actionTaskPool = new ActionTaskPool(2); @@ -125,19 +129,21 @@ public class SamplePreProcessModule { continue; } + if (preReactionStateMgr.isHasReactionCompleted()) { + processPreReactionCompletedGrid(preReactionStateMgr.getReactionCompletedPos()); + continue; + } + if (tubeStateMgrService.isHasSomeToBeProcessedTube()) { TubePosInfo tubePosInfo = getNextToBeProcessedTube(); Boolean isHasEnoughIncubationIDLEPos = incubationPlateStateMgr.isHasEnoughIncubationIDLEPos(tubePosInfo.tube.getProjIds().size()); if (isHasEnoughIncubationIDLEPos) { - - //processTube(tubePosInfo); - + processTube(tubePosInfo); //假装已经处理了试管架 - tubeStateMgrService.pendTube(tubePosInfo.isEmergency, tubePosInfo.tubeIndex); - tubeStateMgrService.changeTubeStateToProcessComplete(); - - + // tubeStateMgrService.pendTube(tubePosInfo.isEmergency, tubePosInfo.tubeIndex); + // tubeStateMgrService.changeTubeStateToProcessComplete(); + continue; } } @@ -150,20 +156,40 @@ public class SamplePreProcessModule { state.isWorking = false; } + private void processPreReactionCompletedGrid(PreReactionPos preReactionPos) throws AppException { + if (preReactionPos == null) + return; + + PreReactionGrid preReactionGrid = preReactionStateMgr.getPreReactionGrid(preReactionPos); + ProjBuildInInfo projBuildInInfo = preReactionGrid.projBuildinInfo; + log.info("处理预反应完成的格子: {}:{}", preReactionGrid.group, preReactionGrid.posIndex); + + docmd("取预反应液", () -> liquidOperationCtrService.takePreReactionLiquid(preReactionPos, true)); + preReactionStateMgr.changeReactionGridStateToUsed(preReactionPos); + + incubationPlateCtrlModule.dropLiquidAndStartIncubating( + preReactionGrid.bindIncubatorPos, + () -> docmd("滴入反应液到孵育盘", liquidOperationCtrService::dropLiquidToReactionPlate), + projBuildInInfo.reactionPlateIncubationTimeMin * 60 + ); + } + + private void processTube(TubePosInfo tubePosInfo) throws AppException { - //change tube state to pending - tubeStateMgrService.pendTube(tubePosInfo.isEmergency, tubePosInfo.tubeIndex); + // + // PendTube + // if (!tubePosInfo.isEmergency) { docmd("移动到下一个试管", () -> tubeFeedingCtrlService.moveTubeToPreProcessPos(tubePosInfo.tubeIndex)); } + tubeStateMgrService.pendTube(tubePosInfo.isEmergency, tubePosInfo.tubeIndex); - + // + // 为该试管中的每一个项目 预定孵育盘位置 + // Tube tube = tubeStateMgrService.getCurProcessingTube(); Assert.isTrue(tube != null, "tube != null"); - - // 预定孵育盘位置 for (var cxt : tube.getPreProcessContexts()) { - //预定孵育盘位置 var incubatorPos = incubationPlateStateMgr.takeOneIncubationIDLEPos((IncubatorPos pos) -> incubationPlateStateMgr.syncCxtInfo(pos, cxt.getSampleInfo(), cxt.getProjBuildinInfo(), cxt.getProjExtInfoCard(), cxt.getConsumableInfo()) ); @@ -173,33 +199,31 @@ public class SamplePreProcessModule { tubeStateMgrService.changeTubeStateToResourceIsReady(); + // + // 执行任务 + // startTask(); actionTaskPool.waitAllDone(); if (actionTaskPool.isHasError()) { - sampleProcessRollback(); - samplePrepareRollback(); + docmd("摇匀模组复位", tubePreProcessCtrlService::resteModule); + docmd("HBOT复位", () -> { + tipOperationCtrlModule.dropTip(); + hbotMoveCtrlService.moveToZero(); + }); } - AppError samplePrepareAppError = actionTaskPool.getError(TaskLine.SamplePrepare); - if (samplePrepareAppError != null && A8kEcodeAnalyzer.isFatalError(samplePrepareAppError)) { - throw AppException.of(samplePrepareAppError); + AppError fatalError = actionTaskPool.getFatalError(); + if (fatalError != null) { + throw AppException.of(fatalError); } - AppError sampleProcessAppError = actionTaskPool.getError(TaskLine.SampleProcess); - if (sampleProcessAppError != null && A8kEcodeAnalyzer.isFatalError(sampleProcessAppError)) { - throw AppException.of(sampleProcessAppError); - } - - if (samplePrepareAppError != null || sampleProcessAppError != null) { - //发生错误,进行回滚 - tubeStateMgrService.changeTubeStateToError(samplePrepareAppError, sampleProcessAppError); + AppError firstError = actionTaskPool.getFirstError(); + if (firstError != null) { + tubeStateMgrService.changeTubeStateToError(firstError); } else { - // 样本处理完成 tubeStateMgrService.changeTubeStateToProcessComplete(); } - - } void startTask() { @@ -245,76 +269,103 @@ public class SamplePreProcessModule { // TubeHolder tubeHolder = tubeStateMgrService.getTubeHolder(); Tube tube = tubeStateMgrService.getCurProcessingTube(); + A8kSamplePos samplePos = ProjectParamUtils.getSamplePos(tubeHolder, tube); List cxts = tube.getPreProcessContexts(); //! 等待样本准备完成 for (ProjectPreProcessContext cxt : cxts) { + boolean finalCxt = cxt.equals(cxts.getLast()); + processTubeCxt(samplePos, tube, cxt, finalCxt); + } + sampleProcessFinishedCondition.setReady(); + + }); + } + + private void processTubeCxt(A8kSamplePos samplePos, Tube tube, ProjectPreProcessContext cxt, Boolean finalCxt) throws AppException { + Assert.isTrue(cxt.getIncubatorPos() != null, "cxt.incubatorPos != null"); - Assert.isTrue(cxt.getIncubatorPos() != null, "cxt.incubatorPos != null"); + PreReactionPos preReactionPos = ProjectParamUtils.getPreReactionPos(cxt); + A8kReactionFlowType reactionFlowType = cxt.getProjBuildinInfo().reactionFlowType; + Integer sampleVol = ProjectParamUtils.getSampleUl(cxt); + ProjBuildInInfo projBuildInInfo = cxt.getProjBuildinInfo(); - boolean finalCxt = cxt.equals(cxts.getLast()); - PreReactionPos preReactionPos = ProjectParamUtils.getPreReactionPos(tubeHolder, tube, cxt); - A8kReactionFlowType reactionFlowType = cxt.getProjBuildinInfo().reactionFlowType; - A8kSamplePos samplePos = ProjectParamUtils.getSamplePos(tubeHolder, tube); - Integer sampleVol = ProjectParamUtils.getSampleUl(cxt); + liquidOperationCtrService.setProjContext(cxt.getProjBuildinInfo(), cxt.getProjExtInfoCard()); - liquidOperationCtrService.setProjContext(cxt.getProjBuildinInfo(), cxt.getProjExtInfoCard()); + switch (reactionFlowType) { + case SampleAndBSAndProbeSubstance -> { + UISender.txInfoMsg(log, "取大瓶缓冲液到探测物质中"); + LargeBufferPos largeBufferPos = LargeBufferPos.of(cxt.getConsumableInfo().group); + Integer largeBSVolume = cxt.getProjBuildinInfo().bigBufferSampleUl; + Assert.notNull(largeBufferPos, "largeBufferPos != null"); + Assert.notNull(preReactionPos, "preReactionPos != null"); + docmd("取大瓶缓冲液", () -> liquidOperationCtrService.takeLargeBottleBufferLiquidToProbeSubstance(largeBufferPos, preReactionPos, largeBSVolume)); + } + case SampleAndBS -> { + Assert.notNull(preReactionPos, "preReactionPos != null"); + docmd("刺破小瓶缓冲液", () -> liquidOperationCtrService.pirceLittleBuffer(preReactionPos)); + } + case SampleOnly -> { + //取TIP + docmd("取TIP", tipOperationCtrlModule::tryTakeTip); + } + } - //预处理 - if (reactionFlowType.equals(A8kReactionFlowType.SampleAndBSAndProbeSubstance)) { - UISender.txInfoMsg(log, "取大瓶缓冲液到探测物质中"); - LargeBufferPos largeBufferPos = LargeBufferPos.of(cxt.getConsumableInfo().group); - Integer largeBSVolume = cxt.getProjBuildinInfo().bigBufferSampleUl; - Assert.notNull(largeBufferPos, "largeBufferPos != null"); - docmd("取大瓶缓冲液", () -> { - liquidOperationCtrService.takeLargeBottleBufferLiquidToProbeSubstance(largeBufferPos, preReactionPos, largeBSVolume); - }); + sampleIsReadyCondition.waitTrue(); - } else if (reactionFlowType.equals(A8kReactionFlowType.SampleAndBS)) { - docmd("刺破小瓶缓冲液", () -> liquidOperationCtrService.pirceLittleBuffer(preReactionPos)); - } + //取样本到小缓冲瓶或者探测物质 + docmd("取样", () -> liquidOperationCtrService.takeSample(samplePos, sampleVol)); - sampleIsReadyCondition.waitTrue(); + //远离取样位置,移动到下一个动作的位置 + switch (reactionFlowType) { + case SampleAndBSAndProbeSubstance, SampleAndBS -> docmd(String.format("移动到预反应位置%s", preReactionPos), () -> hbotMoveExCtrlService.moveToPreReactionPosXY(preReactionPos)); + case SampleOnly -> docmd("移动到滴定位", hbotMoveExCtrlService::moveToDropLiquidPosXY); + } - //取样本到小缓冲瓶或者探测物质 - if (reactionFlowType.equals(A8kReactionFlowType.SampleAndBS)) { - UISender.txInfoMsg(log, "取样"); - docmd("取样", () -> liquidOperationCtrService.takeSampleToPreReactionPos(samplePos, preReactionPos, sampleVol)); - } else if (reactionFlowType.equals(A8kReactionFlowType.SampleAndBSAndProbeSubstance)) { - UISender.txInfoMsg(log, "取样"); - docmd("取样", () -> liquidOperationCtrService.takeSampleToPreReactionPos(samplePos, preReactionPos, sampleVol)); - } + //如果当前项目是这个试管的最后一个项目,则在这里之后,就不再需要样本了,摇匀模组就可以回收样本了 + if (finalCxt) { + sampleProcessFinishedCondition.setReady(); + } - if (finalCxt) {// 在这里之后,就不再需要样本了,摇匀模组就可以回收样本了 - sampleProcessFinishedCondition.setReady(); + switch (reactionFlowType) { + case SampleAndBSAndProbeSubstance, SampleAndBS -> { + + if (projBuildInInfo.getMixedLiquidPreReactionTimeMin() == 0) { + docmd("分配样本到预反应位", () -> liquidOperationCtrService.distributeSampleToPreReactionPos(preReactionPos, false, false)); + + docmd("取预反应液", () -> liquidOperationCtrService.takePreReactionLiquid(preReactionPos, false)); + preReactionStateMgr.syncGridInfo(preReactionPos, tube, tube.getPos()); + preReactionStateMgr.changeReactionGridStateToUsed(preReactionPos); + + incubationPlateCtrlModule.dropLiquidAndStartIncubating( + cxt.getIncubatorPos(), + () -> { + docmd("滴入反应液到孵育盘", liquidOperationCtrService::dropLiquidToReactionPlate); + }, + cxt.getProjBuildinInfo().reactionPlateIncubationTimeMin * 60 + ); + } else { + /* + * 有些项目 样本和缓冲液混合后,需要先反应一定时间后,才开始孵育 + */ + docmd("分配样本到预反应位置", () -> liquidOperationCtrService.distributeSampleToPreReactionPos(preReactionPos, false, true)); + preReactionStateMgr.syncGridInfo(preReactionPos, tube, tube.getPos()); + preReactionStateMgr.changeReactionGridStateToReacting(preReactionPos, projBuildInInfo.getMixedLiquidPreReactionTimeMin() * 60L); } - liquidOperationCtrService.takePreReactionLiquid(preReactionPos); - //开始孵育 - UISender.txInfoMsg(log, "开始孵育"); - Integer incubatedTimeSec = cxt.getProjBuildinInfo().reactionPlateIncubationTimeMin * 60; + + + } + case SampleOnly -> { incubationPlateCtrlModule.dropLiquidAndStartIncubating( cxt.getIncubatorPos(), () -> docmd("取反应液到孵育盘", liquidOperationCtrService::dropLiquidToReactionPlate), - incubatedTimeSec + cxt.getProjBuildinInfo().reactionPlateIncubationTimeMin * 60 ); - //样本使用完,可以回收了 - sampleProcessFinishedCondition.setReady(); + UISender.txInfoMsg(log, "开始孵育"); } - }); - } - - - void samplePrepareRollback() throws AppException { - docmd("摇匀模组复位", tubePreProcessCtrlService::resteModule); - } - - void sampleProcessRollback() throws AppException { - docmd("HBOT复位", () -> { - tipOperationCtrlModule.dropTip(); - hbotMoveCtrlService.moveToZero(); - }); + } } diff --git a/src/main/java/a8k/app/service/peripheral_ctrl/PrinterService.java b/src/main/java/a8k/app/service/peripheral_ctrl/PrinterService.java index 01b26ff..5c8c183 100644 --- a/src/main/java/a8k/app/service/peripheral_ctrl/PrinterService.java +++ b/src/main/java/a8k/app/service/peripheral_ctrl/PrinterService.java @@ -3,6 +3,7 @@ package a8k.app.service.peripheral_ctrl; import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.dao.type.db.ReactionReport; import a8k.app.hardware.channel.PrinterUartChannel; +import a8k.app.i18n.Internationalization; import a8k.app.optalgo.type.ReactionResultStatus; import a8k.app.service.data.ProjInfoMgrService; import a8k.app.service.statemgr.GStateMgrService; @@ -25,12 +26,6 @@ public class PrinterService { private final ProjInfoMgrService projInfoMgrService; private final GStateMgrService gStateMgrService; - String bloodTypeToString(BloodType bloodType) { - return switch (bloodType) { - case WHOLE_BLOOD -> "全血"; - case SERUM_OR_PLASMA -> "血清/血浆"; - }; - } public void printDemoReactionReport() { @@ -97,7 +92,7 @@ public class PrinterService { * */ // 定义日期格式 - if(report == null) { + if (report == null) { return; } @@ -113,7 +108,7 @@ public class PrinterService { printer.printf(" UID: %s\r\n", report.sampleUserid); printer.printf(" BARCODE: %s\r\n", report.sampleBarcode); printer.printf(" \r\n"); - printer.printf(" 样本类型: %s\r\n", bloodTypeToString(report.sampleBloodType)); + printer.printf(" 样本类型: %s\r\n", Internationalization.BloodTypeToString(report.sampleBloodType)); printer.printf(" 项目名称: %s\r\n", report.projName); printer.printf(" 批次号: %s\r\n", report.lotId); printer.printf(" \r\n"); diff --git a/src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java b/src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java index b434711..67338f5 100644 --- a/src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java +++ b/src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java @@ -248,14 +248,16 @@ public class ConsumablesMgrService { * @return 耗材组 */ synchronized public ConsumableInfo reserveConsumable(A8kReactionFlowType flowType, Integer projId) { - ConsumableGroup reactionPlate = null; - ConsumableGroup larBottle = null; - ConsumableInfo littBottle = null; + ConsumableInfo reactionPlate = null; + ConsumableInfo larBottle = null; + ConsumableInfo littBottle = null; switch (flowType) { - case SampleAndBS-> { + case SampleAndBS -> { reactionPlate = reactionPlateContainerStateMgr.reverseOneByProjId(projId); - littBottle = littBottleContainerStateMgr.reverse(reactionPlate); + if (reactionPlate != null) + littBottle = littBottleContainerStateMgr.reverse(reactionPlate.group); + if (reactionPlate == null || littBottle == null) { log.error("预定SampleAndBS耗材失败,可能是没有可用的反应板或小瓶"); reactionPlateContainerStateMgr.bak(reactionPlate); @@ -265,10 +267,13 @@ public class ConsumablesMgrService { stateVersion++; return littBottle; } - case SampleAndBSAndProbeSubstance-> { + case SampleAndBSAndProbeSubstance -> { reactionPlate = reactionPlateContainerStateMgr.reverseOneByProjId(projId); - littBottle = littBottleContainerStateMgr.reverse(reactionPlate); - larBottle = larBottleContainerStateMgr.reverse(reactionPlate); + if (reactionPlate != null) + littBottle = littBottleContainerStateMgr.reverse(reactionPlate.group); + if (reactionPlate != null) + larBottle = larBottleContainerStateMgr.reverse(reactionPlate.group); + if (reactionPlate == null || littBottle == null || larBottle == null) { log.error("预定SampleAndBSAndProbeSubstance耗材失败,可能是没有可用的反应板、小瓶或大瓶"); reactionPlateContainerStateMgr.bak(reactionPlate); @@ -279,6 +284,10 @@ public class ConsumablesMgrService { stateVersion++; return littBottle; } + case SampleOnly -> { + reactionPlate = reactionPlateContainerStateMgr.reverseOneByProjId(projId); + return reactionPlate; + } } return null; } diff --git a/src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java b/src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java index cba2c2c..06564bd 100644 --- a/src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java +++ b/src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java @@ -42,7 +42,7 @@ public class OptScanModuleStateMgr { synchronized public OptScanModuleState getOptScanModule() { if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) { OptScanModuleState virstate = new OptScanModuleState(); - virstate.state = OptScanModuleStateEnum.EMPTY; + virstate.state = OptScanModuleStateEnum.SCANNING; virstate.setBloodType(BloodType.WHOLE_BLOOD); virstate.setSampleBarcode("1234567890"); virstate.setUserid("2250103_003"); diff --git a/src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java b/src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java index 236e144..09607cc 100644 --- a/src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java +++ b/src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java @@ -91,6 +91,15 @@ public class PreReactionStateMgr { return ObjectUtil.cloneByStream(gridGroup); } + public synchronized PreReactionGrid getPreReactionGrid(PreReactionPos preReactionPos) { + PreReactionGridGroup gridGroup = getPreReactionGridGroup(preReactionPos.group); + Assert.notNull(gridGroup, "gridGroup != null"); + if (preReactionPos.index < 0 || preReactionPos.index >= gridGroup.grids.size()) { + return null; + } + return ObjectUtil.cloneByStream(gridGroup.grids.get(preReactionPos.index)); + } + public synchronized Integer getPreReactionGridGroupVersion(ConsumableGroup group) { if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) { return buildFakePreReactionGridGroup(group).version; @@ -138,7 +147,18 @@ public class PreReactionStateMgr { return null; } - public synchronized void changeReactionGridStateToReacting(PreReactionPos preReactionPos, Tube fromTube, Integer off, Long totalReactionTimeS) { + public synchronized void syncGridInfo(PreReactionPos preReactionPos, Tube fromTube, Integer off) { + PreReactionGridGroup gridGroup = getPreReactionGridGroup(preReactionPos.group); + Assert.notNull(gridGroup, "gridGroup != null"); + var grid = gridGroup.grids.get(preReactionPos.index); + grid.projBuildinInfo = fromTube.getPreProcessContexts().get(off).getProjBuildinInfo(); + grid.projExtInfoCard = fromTube.getPreProcessContexts().get(off).getProjExtInfoCard(); + grid.sampleInfo = fromTube.getSampleInfo(); + grid.bindIncubatorPos = fromTube.getPreProcessContexts().get(off).getIncubatorPos(); + gridGroup.version++; + } + + public synchronized void changeReactionGridStateToReacting(PreReactionPos preReactionPos, Long totalReactionTimeS) { PreReactionGridGroup gridGroup = getPreReactionGridGroup(preReactionPos.group); Assert.notNull(gridGroup, "gridGroup != null"); var grid = gridGroup.grids.get(preReactionPos.index); @@ -146,10 +166,6 @@ public class PreReactionStateMgr { grid.totalReactionTime = totalReactionTimeS; grid.startReactionTime = System.currentTimeMillis() / 1000; grid.reactionRemainingTime = totalReactionTimeS; - grid.projBuildinInfo = fromTube.getPreProcessContexts().get(off).getProjBuildinInfo(); - grid.projExtInfoCard = fromTube.getPreProcessContexts().get(off).getProjExtInfoCard(); - grid.sampleInfo = fromTube.getSampleInfo(); - grid.bindIncubatorPos = fromTube.getPreProcessContexts().get(off).getIncubatorPos(); gridGroup.hasSomeGridInReacting = true; gridGroup.version++; } diff --git a/src/main/java/a8k/app/service/statemgr/TubeStateMgr.java b/src/main/java/a8k/app/service/statemgr/TubeStateMgr.java index 1db4320..928c075 100644 --- a/src/main/java/a8k/app/service/statemgr/TubeStateMgr.java +++ b/src/main/java/a8k/app/service/statemgr/TubeStateMgr.java @@ -1,6 +1,7 @@ package a8k.app.service.statemgr; import a8k.app.dao.type.db.DeviceStatistic; +import a8k.app.factory.ZAppPromoptFactory; import a8k.app.service.analyzer.ConsumableStateAnalyzerService; import a8k.app.type.DeviceRunMode; import a8k.app.type.a8k.pos.ConsumableInfo; @@ -221,7 +222,7 @@ public class TubeStateMgr { * 提交后就默认样本已经放置好了,所以需要前台提醒用户需要先暂停设备,放好样本 */ synchronized public void commitEmergencySampleSetting(String userid, String sampleBarcode, BloodType bloodType,// - List projIds, Boolean isVirtual) throws AppException { + List projIds) throws AppException { Tube tube = emergencyTubePos.tube; List projBuildInInfos = new ArrayList<>(); if (projIds.isEmpty()) { @@ -441,19 +442,12 @@ public class TubeStateMgr { curProcessingTube.setState(TubeState.PROCESSING); } - synchronized public void changeTubeStateToError(AppError... errs) { - List errors = new ArrayList<>(); - for (AppError err : errs) { - if (err != null) - errors.add(err); - } - changeTubeStateToError(errors); - } - synchronized public void changeTubeStateToError(List errors) { - log.error("试管 状态->错误 SampleId:{} \n{}", curProcessingTube.getSampleId(), ZJsonHelper.objectToJson(errors)); + synchronized public void changeTubeStateToError(AppError error) { + log.error("试管 状态->错误 SampleId:{} \n{}", curProcessingTube.getSampleId(), ZJsonHelper.objectToJson(error)); curProcessingTube.setState(TubeState.ERROR); - curProcessingTube.setErrors(errors); + curProcessingTube.setError(error); + curProcessingTube.setErrorInfo(ZAppPromoptFactory.buildAppPromopt(error)); curProcessingTube = null; } diff --git a/src/main/java/a8k/app/service/statemgr/consumables_mgr/LarBottleContainerStateMgr.java b/src/main/java/a8k/app/service/statemgr/consumables_mgr/LarBottleContainerStateMgr.java index f1c5bee..756c8ba 100644 --- a/src/main/java/a8k/app/service/statemgr/consumables_mgr/LarBottleContainerStateMgr.java +++ b/src/main/java/a8k/app/service/statemgr/consumables_mgr/LarBottleContainerStateMgr.java @@ -82,12 +82,11 @@ public class LarBottleContainerStateMgr { return totalNum; } - synchronized public ConsumableGroup reverse(ConsumableGroup group) { + synchronized public ConsumableInfo reverse(ConsumableGroup group) { if (group == null) { return null; } LarBottleContainer container = this.containers[group.off]; - if (!container.isInstall) { return null; } @@ -97,7 +96,8 @@ public class LarBottleContainerStateMgr { } container.reserveNum++; Assert.isTrue(container.reserveNum <= container.num, "Reserve number cannot exceed total number"); - return group; + return new ConsumableInfo(container.lotId, group, AppConstant.CONSUMABLE_NUM - (container.num - (container.reserveNum - 1))); + } synchronized public void bak(ConsumableInfo consumable) { diff --git a/src/main/java/a8k/app/service/statemgr/consumables_mgr/ReactionPlateContainerStateMgr.java b/src/main/java/a8k/app/service/statemgr/consumables_mgr/ReactionPlateContainerStateMgr.java index f512eee..da300d5 100644 --- a/src/main/java/a8k/app/service/statemgr/consumables_mgr/ReactionPlateContainerStateMgr.java +++ b/src/main/java/a8k/app/service/statemgr/consumables_mgr/ReactionPlateContainerStateMgr.java @@ -77,7 +77,7 @@ public class ReactionPlateContainerStateMgr { return totalNum; } - synchronized public ConsumableGroup reverseOneByProjId(Integer projId) { + synchronized public ConsumableInfo reverseOneByProjId(Integer projId) { for (ConsumableGroup group : ConsumableGroup.values()) { ReactionPlateContainer container = containers[group.off]; if (container.isInstall && container.projId.equals(projId)) { @@ -85,7 +85,7 @@ public class ReactionPlateContainerStateMgr { log.debug("getOneByProjId: group={}, projId={}", group, projId); container.reserveNum++; Assert.isTrue(container.reserveNum <= container.num, "Reserve number cannot exceed total number"); - return group; + return new ConsumableInfo(container.lotId, group, AppConstant.CONSUMABLE_NUM - (container.num - (container.reserveNum - 1))); } } } @@ -127,6 +127,9 @@ public class ReactionPlateContainerStateMgr { } synchronized public void bak(ConsumableInfo consumable) { + if (consumable == null || consumable.group == null) { + return; + } bak(consumable.group); } diff --git a/src/main/java/a8k/app/service/utils/ProjInfoReader.java b/src/main/java/a8k/app/service/utils/ProjInfoReader.java deleted file mode 100644 index 9467d5c..0000000 --- a/src/main/java/a8k/app/service/utils/ProjInfoReader.java +++ /dev/null @@ -1,32 +0,0 @@ -package a8k.app.service.utils; - -import a8k.app.type.a8k.BloodType; -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) { - - if (bloodType.equals(BloodType.WHOLE_BLOOD)) { - if (isEffectiveValue(extInfoCard.wBloodSampleVolUl)) { - return extInfoCard.wBloodSampleVolUl; - } else { - return buildinInfo.wBloodSampleVolUl; - } - } else { - if (isEffectiveValue(extInfoCard.serumSampleVolUl)) { - return extInfoCard.serumSampleVolUl; - } else { - return buildinInfo.serumSampleVolUl; - } - - } - } - - private static Boolean isEffectiveValue(Integer val) { - return val != null && val >= 0; - } -} diff --git a/src/main/java/a8k/app/type/a8k/BloodType.java b/src/main/java/a8k/app/type/a8k/BloodType.java index 8799263..57fe3a7 100644 --- a/src/main/java/a8k/app/type/a8k/BloodType.java +++ b/src/main/java/a8k/app/type/a8k/BloodType.java @@ -5,8 +5,13 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = """ 血液类型: * WHOLE_BLOOD:全血 - * SERUM_OR_PLASMA:血清或者血浆""") + * SERUM_OR_PLASMA:血清或者血浆 + * FECES:粪便 + """) public enum BloodType { WHOLE_BLOOD,//全血 SERUM_OR_PLASMA,//血清或者血浆 + FECES,//粪便 + + } diff --git a/src/main/java/a8k/app/type/a8k/SupportBloodType.java b/src/main/java/a8k/app/type/a8k/SupportBloodType.java index 3ad61ac..d0727f9 100644 --- a/src/main/java/a8k/app/type/a8k/SupportBloodType.java +++ b/src/main/java/a8k/app/type/a8k/SupportBloodType.java @@ -1,18 +1,18 @@ package a8k.app.type.a8k; - -//ID卡中的类型 -public enum SupportBloodType { - WHOLE_BLOOD(0),//全血 - PLASMA(1),//血浆 - SERUM(2), - SERUM_AND_PLASMA(3),//血清或者血浆 - WHOLE_BLOOD_AND_PLASMA(4),//全血和血浆 - WHOLE_BLOOD_AND_SERUM_AND_PLASMA(5),//全血和血清或者血浆 - URINE(6),//尿液 - FAECES(7),//粪便 - ; - final int index; - SupportBloodType(int index) { - this.index = index; - } -} +// +////ID卡中的类型 +//public enum SupportBloodType { +// WHOLE_BLOOD(0),//全血 +// PLASMA(1),//血浆 +// SERUM(2), +// SERUM_AND_PLASMA(3),//血清或者血浆 +// WHOLE_BLOOD_AND_PLASMA(4),//全血和血浆 +// WHOLE_BLOOD_AND_SERUM_AND_PLASMA(5),//全血和血清或者血浆 +// URINE(6),//尿液 +// FAECES(7),//粪便 +// ; +// final int index; +// SupportBloodType(int index) { +// this.index = index; +// } +//} diff --git a/src/main/java/a8k/app/type/a8k/proj/A8kReactionFlowType.java b/src/main/java/a8k/app/type/a8k/proj/A8kReactionFlowType.java index 59748ff..ad74bcb 100644 --- a/src/main/java/a8k/app/type/a8k/proj/A8kReactionFlowType.java +++ b/src/main/java/a8k/app/type/a8k/proj/A8kReactionFlowType.java @@ -29,13 +29,31 @@ public enum A8kReactionFlowType { * 滴定 */ SampleAndBSAndProbeSubstance(2, 2),//样本,大瓶缓冲液,探测物质反应 + + /* + * + * 流程: + * 取TIP + * 取样本 + * 放入反应板中 + */ + SampleOnly(3, 1) //仅样本反应 ; public final int tipUseNum; - public final int valInIdCard; + public final int valInIdCard; // ID卡中的数值 A8kReactionFlowType(int valInIdCard, int tipUseNum) { this.tipUseNum = tipUseNum; this.valInIdCard = valInIdCard; } + static public Integer getSupportTipPrepareNumEachProject() { + int max = 0; + for (A8kReactionFlowType type : A8kReactionFlowType.values()) { + if (type.tipUseNum > max) { + max = type.tipUseNum; + } + } + return max + 1; + } } 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 04d1b8f..0a7397a 100644 --- a/src/main/java/a8k/app/type/a8k/state/Tube.java +++ b/src/main/java/a8k/app/type/a8k/state/Tube.java @@ -6,6 +6,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.combination.ProjBuildInInfo; +import a8k.app.type.ui.ZAppPromopt; import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -40,13 +41,14 @@ public class Tube implements Serializable { // @Schema(description = "样本被处理的状态") - TubeState state = TubeState.EMPTY; //样本被处理的状态 + TubeState state = TubeState.EMPTY; //样本被处理的状态 @Schema(description = "样本处理的错误信息") - List errors = new ArrayList<>(); //错误信息 + AppError error = null; + ZAppPromopt errorInfo = null; //错误提示 List preProcessContexts = new ArrayList<>(); //预处理上下文 @JsonIgnore - A8kTubeHolderType tubeHolderType = null; + A8kTubeHolderType tubeHolderType = null; @JsonIgnore List projBuildInInfos = new ArrayList<>(); @@ -65,7 +67,7 @@ public class Tube implements Serializable { this.projIds.clear(); this.projInfo.clear(); this.state = TubeState.EMPTY; - this.errors.clear(); + this.error = null; this.preProcessContexts.clear(); } diff --git a/src/main/java/a8k/app/type/error/ConsumablesScanReportErrorType.java b/src/main/java/a8k/app/type/error/ConsumablesScanReportErrorType.java index c260cb9..05d28bd 100644 --- a/src/main/java/a8k/app/type/error/ConsumablesScanReportErrorType.java +++ b/src/main/java/a8k/app/type/error/ConsumablesScanReportErrorType.java @@ -16,6 +16,7 @@ import io.swagger.v3.oas.annotations.media.Schema; * REACTION_PLATE_2D_CODE_FORMATE_ERROR:反应板二维码格式错误 * CODE_ERROR_PROJINFO_IS_ERROR:代码错误,项目信息异常 * UN_SUPPORT_PROJ:不支持的项目 + * UN_MATCHED_CONSUMABLES:耗材不匹配 """) public enum ConsumablesScanReportErrorType { PASS, //通过 @@ -34,4 +35,6 @@ public enum ConsumablesScanReportErrorType { CODE_ERROR_PROJINFO_IS_ERROR,//代码错误,项目信息异常 UN_SUPPORT_PROJ,//不支持的项目 + + PROJ_ONLY_NEED_REACTION_PLATE, //当前项目只需要反应板 } diff --git a/src/main/java/a8k/app/utils/ActionTaskPool.java b/src/main/java/a8k/app/utils/ActionTaskPool.java index a0a511f..2873aba 100644 --- a/src/main/java/a8k/app/utils/ActionTaskPool.java +++ b/src/main/java/a8k/app/utils/ActionTaskPool.java @@ -1,6 +1,7 @@ package a8k.app.utils; import a8k.OS; +import a8k.app.service.analyzer.A8kEcodeAnalyzer; import a8k.app.type.error.AECodeError; import a8k.app.type.error.AppError; import a8k.app.type.exception.AppException; @@ -28,9 +29,9 @@ public class ActionTaskPool { Boolean errorFlag = false; List> futures = new ArrayList<>(); - Map, AppError> errorMap = new HashMap<>(); - - List boolConditions = new ArrayList<>(); + Map, AppError> errorMap = new HashMap<>(); + List errors = new ArrayList<>(); + List boolConditions = new ArrayList<>(); public ActionTaskPool(Integer threadNum) { executor = new ThreadPoolExecutor(threadNum, threadNum, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10)); @@ -62,11 +63,29 @@ public class ActionTaskPool { errorFlag = false; errorMap.clear(); futures.clear(); + errors.clear(); for (var boolCondition : boolConditions) { boolCondition.clear(); } } + public AppError getFatalError() { + for (var error : errorMap.values()) { + if (A8kEcodeAnalyzer.isFatalError(error.code)) { + return error; + } + } + return null; + } + + public AppError getFirstError() { + if (errorMap.isEmpty()) { + return null; + } + return errors.get(0); + } + + public AppError getError(Enum taskLineMaskter) { return errorMap.get(taskLineMaskter); } @@ -83,7 +102,6 @@ public class ActionTaskPool { log.info("Line {} done", taskLineMaskter.name()); } catch (Exception e) { exception = e; - errorFlag = true; } if (exception != null) { @@ -91,11 +109,15 @@ public class ActionTaskPool { if (!appException.error.code.equals(A8kEcode.ZAPP_INTERRUPT_EXCEPTION)) { log.error("do {}.afterDoAction catch exception", taskLineMaskter.name(), appException); errorMap.put(taskLineMaskter, appException.error); + errors.add(appException.error); } } else { log.error("do {}.afterDoAction catch exception", taskLineMaskter.name(), exception); errorMap.put(taskLineMaskter, new AECodeError(exception)); + errors.add(new AECodeError(exception)); } + // this flag is used to interrupt other thread by check in condition val + errorFlag = true; } diff --git a/src/main/java/a8k/app/utils/ProjectParamUtils.java b/src/main/java/a8k/app/utils/ProjectParamUtils.java index a5e0d18..e9c7e89 100644 --- a/src/main/java/a8k/app/utils/ProjectParamUtils.java +++ b/src/main/java/a8k/app/utils/ProjectParamUtils.java @@ -39,7 +39,7 @@ public class ProjectParamUtils { return samplePos; } - static public PreReactionPos getPreReactionPos(TubeHolder tubeHolder, Tube tube, ProjectPreProcessContext cxt) { + static public PreReactionPos getPreReactionPos( ProjectPreProcessContext cxt) { A8kReactionFlowType reactionFlowType = cxt.getProjBuildinInfo().reactionFlowType; PreReactionPos preReactionPos = new PreReactionPos(); switch (reactionFlowType) { @@ -47,11 +47,19 @@ public class ProjectParamUtils { preReactionPos.type = LittleBottleConsumableType.BufferSolution; preReactionPos.group = cxt.getConsumableInfo().group; preReactionPos.index = cxt.getConsumableInfo().pos; + return preReactionPos; } case SampleAndBSAndProbeSubstance -> { preReactionPos.type = LittleBottleConsumableType.ProbeSubstance; preReactionPos.group = cxt.getConsumableInfo().group; preReactionPos.index = cxt.getConsumableInfo().pos; + return preReactionPos; + } + case SampleOnly -> { + preReactionPos.type = null; + preReactionPos.group = null; + preReactionPos.index = 0; + return null; } } return preReactionPos; @@ -62,15 +70,23 @@ public class ProjectParamUtils { switch (cxt.getSampleInfo().bloodType) { case WHOLE_BLOOD -> { sampleUl = cxt.getProjBuildinInfo().wBloodSampleVolUl; - if (cxt.getProjExtInfoCard().wBloodSampleVolUl > 0) { + if (sampleUl == 0) + sampleUl = cxt.getProjBuildinInfo().defaultSampleVolUl; + if (cxt.getProjExtInfoCard().wBloodSampleVolUl > 0) sampleUl = cxt.getProjExtInfoCard().wBloodSampleVolUl; - } } case SERUM_OR_PLASMA -> { sampleUl = cxt.getProjBuildinInfo().serumSampleVolUl; - if (cxt.getProjExtInfoCard().serumSampleVolUl > 0) { + if (sampleUl == 0) + sampleUl = cxt.getProjBuildinInfo().defaultSampleVolUl; + if (cxt.getProjExtInfoCard().serumSampleVolUl > 0) sampleUl = cxt.getProjExtInfoCard().serumSampleVolUl; - } + } + case FECES -> { + sampleUl = cxt.getProjBuildinInfo().fecesSampleVolUl; + if (sampleUl == 0) + sampleUl = cxt.getProjBuildinInfo().defaultSampleVolUl; + } } ; return sampleUl; diff --git a/src/main/java/a8k/extui/page/debug/P01EmergencyTubeDebugPage.java b/src/main/java/a8k/extui/page/debug/P01EmergencyTubeDebugPage.java index 499993a..facb7f8 100644 --- a/src/main/java/a8k/extui/page/debug/P01EmergencyTubeDebugPage.java +++ b/src/main/java/a8k/extui/page/debug/P01EmergencyTubeDebugPage.java @@ -69,8 +69,7 @@ public class P01EmergencyTubeDebugPage { setting.userid, setting.sampleBarcode, setting.bloodType, - setting.projIds, - false + setting.projIds ); } diff --git a/src/main/java/a8k/extui/page/extapp/A8kOptVerification.java b/src/main/java/a8k/extui/page/extapp/A8kOptVerification.java index 3f33942..5a8b6da 100644 --- a/src/main/java/a8k/extui/page/extapp/A8kOptVerification.java +++ b/src/main/java/a8k/extui/page/extapp/A8kOptVerification.java @@ -74,7 +74,7 @@ public class A8kOptVerification { return switch (bloodType) { case WHOLE_BLOOD -> "全血"; case SERUM_OR_PLASMA -> "血清/血浆"; - default -> "未知"; + case FECES -> "粪便"; }; } @@ -102,6 +102,7 @@ public class A8kOptVerification { page.addFunction("进行一次光学扫描(自动推板,丢板)", this::autoScanAndDownloadScanResult); extApiPageMgr.addPage(page); } + public Map getProjInfoBreifList() throws AppException { var allproj = projInfoMgrService.getAllProjBuildInInfo(); Map result = new java.util.HashMap<>(); diff --git a/src/main/java/a8k/extui/page/test/verification/P34LiquidOperationTestPage.java b/src/main/java/a8k/extui/page/test/verification/P34LiquidOperationTestPage.java index c3e2c82..8ccbc3c 100644 --- a/src/main/java/a8k/extui/page/test/verification/P34LiquidOperationTestPage.java +++ b/src/main/java/a8k/extui/page/test/verification/P34LiquidOperationTestPage.java @@ -23,11 +23,11 @@ public class P34LiquidOperationTestPage { @Resource LiquidOperationCtrService liquidOperationCtrService; @Resource - TurnableMoveCtrlService turnableMoveCtrlService; + TurnableMoveCtrlService turnableMoveCtrlService; @Resource - TipOperationCtrlModule tipOperationCtrlModule; + TipOperationCtrlModule tipOperationCtrlModule; @Resource - ExtApiPageMgr extApiPageMgr; + ExtApiPageMgr extApiPageMgr; // @@ -46,23 +46,8 @@ public class P34LiquidOperationTestPage { liquidOperationCtrService.takeLargeBottleBufferLiquidToProbeSubstance(from, topos, ul); } - public void takeSampleToProbeSubstance(A8kSamplePos from, ConsumableGroup toGroup, Integer toIndex, Integer ul) throws AppException { - PreReactionPos topos = new PreReactionPos(LittleBottleConsumableType.ProbeSubstance, toGroup, toIndex); - liquidOperationCtrService.takeSampleToPreReactionPos(from, topos, ul); - } - - public void takePreReactionLiquidFromProbeSubstance(ConsumableGroup toGroup, Integer toIndex) throws AppException { - PreReactionPos pos = new PreReactionPos(LittleBottleConsumableType.ProbeSubstance, toGroup, toIndex); - liquidOperationCtrService.takePreReactionLiquid(pos); - } - public void takeSampleOnly(A8kSamplePos from, Integer ul) throws AppException { - liquidOperationCtrService.takeSampleOnly(from, ul); - } - - public void takeSampleToLittleBuffer(A8kSamplePos from, ConsumableGroup toGroup, Integer toIndex, Integer ul) throws AppException { - PreReactionPos topos = new PreReactionPos(LittleBottleConsumableType.BufferSolution, toGroup, toIndex); - liquidOperationCtrService.takeSampleToPreReactionPos(from, topos, ul); + liquidOperationCtrService.takeSample(from, ul); } public void pirceLittleBuffer(ConsumableGroup toGroup, Integer toIndex) throws AppException { @@ -70,10 +55,6 @@ public class P34LiquidOperationTestPage { liquidOperationCtrService.pirceLittleBuffer(pos); } - public void takePreReactionLiquidFromSmallBottleBuffer(ConsumableGroup toGroup, Integer toIndex) throws AppException { - PreReactionPos pos = new PreReactionPos(LittleBottleConsumableType.BufferSolution, toGroup, toIndex); - liquidOperationCtrService.takePreReactionLiquid(pos); - } public void dropLiquidToReactionPlate(IncubatorPos pos) throws AppException { turnableMoveCtrlService.trunableMoveToDropLiquidPos(pos); @@ -88,13 +69,13 @@ public class P34LiquidOperationTestPage { cfg.addFunction("丢Tip", this::dropTip); cfg.newGroup("液体操作-大瓶缓冲液/探测物质"); cfg.addFunction("取大瓶缓冲液到探测物质位置", this::takeLargeBottleBufferLiquidToProbeSubstance); - cfg.addFunction("取样品到探测物质位置", this::takeSampleToProbeSubstance); - cfg.addFunction("取反应液", this::takePreReactionLiquidFromProbeSubstance); + // cfg.addFunction("取样品到探测物质位置", this::takeSampleToProbeSubstance); + // cfg.addFunction("取反应液", this::takePreReactionLiquidFromProbeSubstance); cfg.addFunction("滴反应液到反应板上", this::dropLiquidToReactionPlate); cfg.newGroup("液体操作-小瓶缓冲液"); cfg.addFunction("刺小瓶缓冲液", this::pirceLittleBuffer); - cfg.addFunction("取样品到小瓶缓冲液", this::takeSampleToLittleBuffer); - cfg.addFunction("取反应液", this::takePreReactionLiquidFromSmallBottleBuffer); + // cfg.addFunction("取样品到小瓶缓冲液", this::takeSampleToLittleBuffer); + // cfg.addFunction("取反应液", this::takePreReactionLiquidFromSmallBottleBuffer); cfg.addFunction("滴反应液到反应板上", this::dropLiquidToReactionPlate); cfg.newGroup("其他"); cfg.addFunction("取样本(Only)", this::takeSampleOnly); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index da50954..1819e99 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,17 +1,17 @@ -server: - port: 80 +# server.port: 8082 +server.port: 80 -#device.runmode: "RealMode" a8k.enableTemperatureCtrl: false +# device.runmode: "VirtualMode" device.runmode: "RealMode" device.enableCanBus: true -iflytophald: - # ip: 192.168.8.10 - ip: 192.168.8.10 -# ip: 127.0.0.1 - cmdch.port: 19004 - datach.port: 19005 + +# ip: 192.168.8.10 +iflytophald.ip: 192.168.8.10 +# iflytophald.ip: 127.0.0.1 +iflytophald.cmdch.port: 19004 +iflytophald.datach.port: 19005 #hardware.canbus.url: ws://127.0.0.1:19005 diff --git a/src/main/resources/db/zapp_a8k_project_info.csv b/src/main/resources/db/zapp_a8k_project_info.csv index ed634fa..d69483e 100644 --- a/src/main/resources/db/zapp_a8k_project_info.csv +++ b/src/main/resources/db/zapp_a8k_project_info.csv @@ -1,32 +1,32 @@ -id,projId,projName,projShortName,subProjNum,reactionTemperature,color,reactionFlowType,wBloodSampleVolUl,serumSampleVolUl,shakeTimes,bigBufferSampleUl,reactionPlateIncubationTimeMin,reactionPlateDropletVolUl,mixedLiquidMixingTimes,mixedLiquidMixingVolUl -1,1,hsCRP,CA,1,25,#FFC0CB,SampleAndBS,10,10,3,0,3,75,5,200 -2,2,PCT,PC,1,25,#DC143C,SampleAndBS,150,150,3,0,12,75,5,200 -3,3,TSH,TS,1,25,#DB7093,SampleAndBSAndProbeSubstance,150,150,3,75,12,75,5,150 -4,4,PRL,PL,1,25,#FF69B4,SampleAndBS,75,75,3,0,10,75,5,200 -5,5,T3,T3,1,25,#FF1493,SampleAndBSAndProbeSubstance,75,75,3,75,8,75,5,150 -6,6,T4,T4,1,25,#C71585,SampleAndBSAndProbeSubstance,75,75,3,75,8,75,5,150 -7,7,Total β hCG,HC,1,25,#DA70D6,SampleAndBS,50,30,3,0,15,75,5,200 -8,8,LH,LH,1,25,#D8BFD8,SampleAndBS,150,150,3,0,15,75,5,200 -9,9,FSH,FS,1,25,#DDA0DD,SampleAndBS,150,150,3,0,15,75,5,200 -10,10,Progesterone,PG,1,25,#EE82EE,SampleAndBS,30,30,3,0,15,75,5,200 -12,12,Tn-I plus,TG,1,25,#FF00FF,SampleAndBSAndProbeSubstance,50,50,3,150,12,75,5,150 -13,13,NT-proBNP,NB,1,25,#8B008B,SampleAndBSAndProbeSubstance,10,10,3,150,12,75,5,150 -14,14,CK-MB,CK,1,25,#800080,SampleAndBS,75,75,3,0,12,75,5,200 -15,15,Myoglobin,MY,1,25,#BA55D3,SampleAndBS,10,10,3,0,12,75,5,200 -16,16,D-Dimer,DD,1,25,#9400D3,SampleAndBS,10,10,3,0,12,75,5,200 -17,17,HbAlC,HB,1,25,#9932CC,SampleAndBSAndProbeSubstance,5,5,3,100,12,75,5,150 -18,18,PCT plus,PP,1,25,#4B0082,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150 -20,20,Tn-I/CK-MB/Myoglobin,CT,3,25,#9370DB,SampleAndBSAndProbeSubstance,75,75,3,150,12,75,5,150 -22,22,PCT/hsCRP,PR,2,25,#6A5ACD,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150 -24,24,SAA,SA,1,25,#E6E6FA,SampleAndBS,10,10,3,0,3,75,5,200 -25,25,AMH,AM,1,25,#F8F8FF,SampleAndBSAndProbeSubstance,50,50,3,150,12,75,5,150 -26,26,SAA/CRP,SC,2,25,#0000FF,SampleAndBS,10,10,3,0,3,75,5,200 -27,27,Vitamin D,VD,1,25,#0000FF,SampleAndBSAndProbeSubstance,30,30,3,150,12,75,5,150 -33,33,ST2,ST,1,25,#6495ED,SampleAndBSAndProbeSubstance,75,75,3,150,12,75,5,150 -36,36,MxA,MX,1,25,#708090,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150 -48,48,IL-6,IL,1,25,#AFEEEE,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150 -49,49,Gastrin 17,GA,1,25,#00FFFF,SampleAndBSAndProbeSubstance,50,50,3,150,15,75,5,150 -50,50,Pepsinogen I/II,PS,2,25,#00FFFF,SampleAndBSAndProbeSubstance,10,10,3,150,10,75,5,150 -52,52,NT-proBNP/ST2,NS,2,25,#2F4F4F,SampleAndBSAndProbeSubstance,10,10,3,150,12,75,5,150 -54,54,Troponin T,TT,1,25,#008080,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150 -55,55,BNP,BP,1,25,#48D1CC,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150 +id,projId,projName,projShortName,subProjNum,reactionTemperature,color,reactionFlowType,supportBloodTypes,defaultSampleVolUl,wBloodSampleVolUl,serumSampleVolUl,fecesSampleVolUl,shakeTimes,bigBufferSampleUl,reactionPlateIncubationTimeMin,reactionPlateDropletVolUl,mixedLiquidMixingTimes,mixedLiquidMixingVolUl,mixedLiquidPreReactionTimeMin,mixedLiquidPreReactionTimeMin +2,2,PCT,PC,1,25,#DC143C,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",150,0,0,0,3,0,12,75,5,200,0,0 +1,1,hsCRP,CA,1,25,#FFC0CB,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,0,3,75,5,200,0,0 +7,7,Total β hCG,HC,1,25,#DA70D6,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",50,50,30,0,3,0,15,75,5,200,0,0 +10,10,Progesterone,PG,1,25,#EE82EE,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",30,0,0,0,3,0,15,75,5,200,0,0 +14,14,CK-MB,CK,1,35,#800080,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,0,12,75,5,200,0,0 +16,16,D-Dimer,DD,1,25,#9400D3,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,0,12,75,5,200,0,0 +15,15,Myoglobin,MY,1,25,#BA55D3,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,0,12,75,5,200,0,0 +13,13,NT-proBNP,NB,1,25,#8B008B,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,150,12,75,5,150,0,0 +12,12,Tn-I plus,TG,1,25,#FF00FF,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",50,0,0,0,3,150,12,75,5,150,0,0 +22,22,PCT/hsCRP,PR,2,25,#6A5ACD,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0 +20,20,Tn-I/CK-MB/Myoglobin,CT,3,25,#9370DB,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,150,12,75,5,150,0,0 +24,24,SAA,SA,1,25,#E6E6FA,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,0,3,75,5,200,0,0 +33,33,ST2,ST,1,25,#6495ED,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,150,12,75,5,150,0,0 +25,25,AMH,AM,1,25,#F8F8FF,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",50,0,0,0,3,150,12,75,5,150,0,0 +9,9,FSH,FS,1,25,#DDA0DD,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",150,0,0,0,3,0,15,75,5,200,0,0 +8,8,LH,LH,1,25,#D8BFD8,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",150,0,0,0,3,0,15,75,5,200,0,0 +4,4,PRL,PL,1,25,#FF69B4,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,0,10,75,5,200,0,0 +3,3,TSH,TS,1,25,#DB7093,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",150,0,0,0,3,75,12,75,5,150,0,0 +5,5,T3,T3,1,25,#FF1493,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,75,8,75,5,150,0,0 +6,6,T4,T4,1,25,#C71585,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,75,8,75,5,150,0,0 +17,17,HbAlC,HB,1,25,#9932CC,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",5,0,0,0,3,100,12,75,5,150,0,0 +26,26,SAA/CRP,SC,2,25,#0000FF,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,0,3,75,5,200,0,0 +48,48,IL-6,IL,1,25,#AFEEEE,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0 +50,50,Pepsinogen I/II,PS,2,25,#00FFFF,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,150,10,75,5,150,0,0 +55,55,BNP,BP,1,25,#48D1CC,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0 +54,54,Troponin T,TT,1,25,#008080,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0 +49,49,Gastrin 17,GA,1,25,#00FFFF,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",50,0,0,0,3,150,15,75,5,150,0,0 +52,52,NT-proBNP/ST2,NS,2,25,#2F4F4F,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,150,12,75,5,150,0,0 +18,18,PCT plus,PP,1,25,#4B0082,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0 +27,27,Vitamin D,VD,1,25,#0000FF,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",30,0,0,0,3,150,12,75,5,150,0,0 +36,36,MxA,MX,1,25,#708090,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0