6 changed files with 329 additions and 15 deletions
-
2src/main/java/a8k/app/a8ktype/state/SampleInfo.java
-
8src/main/java/a8k/app/service/mainctrl/mainflowctrl/MainFlowCtrlScheduler.java
-
19src/main/java/a8k/app/service/mainctrl/mainflowctrl/processer/MainFlowStateChangeProcesser.java
-
8src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java
-
8src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java
-
289src/main/java/a8k/extui/page/extapp/OptFullFlowVerificationPage.java
@ -0,0 +1,289 @@ |
|||||
|
package a8k.extui.page.extapp; |
||||
|
|
||||
|
import a8k.OS; |
||||
|
import a8k.app.a8kproj.A8kReactionResultComputer; |
||||
|
import a8k.app.a8kproj.optalgo.type.OptScanResult; |
||||
|
import a8k.app.a8ktype.device.*; |
||||
|
import a8k.app.a8ktype.exception.AppException; |
||||
|
import a8k.app.a8ktype.param.type.A8kSamplePos; |
||||
|
import a8k.app.a8ktype.state.SampleInfo; |
||||
|
import a8k.app.a8ktype.type.ReactionResult; |
||||
|
import a8k.app.a8ktype.type.TubeHolderScanResult; |
||||
|
import a8k.app.dao.db.type.ProjExtInfoCard; |
||||
|
import a8k.app.dao.db.type.a8kidcard.zenum.A8kReactionFlowType; |
||||
|
import a8k.app.hardware.driver.PipetteCtrlDriver; |
||||
|
import a8k.app.service.bases.AppEventBusService; |
||||
|
import a8k.app.service.bases.FrontEndMessageBoxAndEventMgr; |
||||
|
import a8k.app.service.data.ProjIdCardInfoMgrService; |
||||
|
import a8k.app.service.data.ProjInfoMgrService; |
||||
|
import a8k.app.service.data.ReactionRecordMgrService; |
||||
|
import a8k.app.service.lowerctrl.*; |
||||
|
import a8k.app.utils.ProjBuildinInfo; |
||||
|
import a8k.app.utils.ProjInfo; |
||||
|
import a8k.app.utils.ProjInfoReader; |
||||
|
import a8k.app.utils.ZDateUtils; |
||||
|
import a8k.extui.mgr.ExtApiPageMgr; |
||||
|
import a8k.extui.type.ExtApiStatu; |
||||
|
import jakarta.annotation.PostConstruct; |
||||
|
import jakarta.annotation.Resource; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.util.Assert; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Date; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Component |
||||
|
public class OptFullFlowVerificationPage { |
||||
|
|
||||
|
@Resource |
||||
|
TubeFeedingCtrlService tubeFeedingCtrlService; |
||||
|
|
||||
|
@Resource |
||||
|
TubePreProcesModuleExCtrlService tubePreProcesModuleExCtrlService; |
||||
|
|
||||
|
TubeHolderScanResult tubeHolderScanResult; |
||||
|
|
||||
|
|
||||
|
@Resource |
||||
|
PlateBoxCtrlService plateBoxCtrlService; |
||||
|
@Resource |
||||
|
OptScanModuleCtrlService optScanModuleCtrlService; |
||||
|
@Resource |
||||
|
PipetteCtrlDriver pipetteCtrlDriver; |
||||
|
@Resource |
||||
|
HbotMoveExCtrlService hbotMoveExCtrlService; |
||||
|
@Resource |
||||
|
LiquidOperationCtrlService liquidOperationCtrlService; |
||||
|
@Resource |
||||
|
TurnableMoveCtrlService turnableMoveCtrlService; |
||||
|
|
||||
|
@Resource |
||||
|
ProjIdCardInfoMgrService projIdCardInfoMgrService; |
||||
|
@Resource |
||||
|
ProjInfoMgrService projInfoMgrService; |
||||
|
@Resource |
||||
|
AppEventBusService appEventBusService; |
||||
|
|
||||
|
@Resource |
||||
|
FrontEndMessageBoxAndEventMgr frontEndMessageBoxAndEventMgr; |
||||
|
@Autowired |
||||
|
private ReactionRecordMgrService reactionRecordMgrService; |
||||
|
|
||||
|
|
||||
|
// |
||||
|
//Config |
||||
|
// |
||||
|
static public class Context { |
||||
|
public SampleInfo sampleInfo = new SampleInfo(); |
||||
|
public ProjBuildinInfo projBuildinInfo; |
||||
|
public ProjExtInfoCard projExtInfoCard; |
||||
|
public A8kSamplePos samplePos = A8kSamplePos.EmergencyTubePos; |
||||
|
public ConsumableGroup consumableGroup = ConsumableGroup.CG1; |
||||
|
public Integer consumablePosOff = 0; |
||||
|
public IncubatorPos incubatorPos = IncubatorPos.SPACE01; |
||||
|
|
||||
|
public List<ReactionResult> results = new ArrayList<>(); |
||||
|
public Boolean isInit = false; |
||||
|
} |
||||
|
|
||||
|
static public class State { |
||||
|
public Integer incubateRemainTime; |
||||
|
} |
||||
|
|
||||
|
Context cxt = new Context(); |
||||
|
State state = new State(); |
||||
|
|
||||
|
|
||||
|
@ExtApiStatu(name = "", group = "样本信息", order = 1, minWidth = "33.3%") |
||||
|
public SampleInfo showSampleInfo() { |
||||
|
return cxt.sampleInfo; |
||||
|
} |
||||
|
|
||||
|
@ExtApiStatu(name = "", group = "项目信息", order = 2, minWidth = "33.3%") |
||||
|
public ProjBuildinInfo showProjInfo() { |
||||
|
return cxt.projBuildinInfo; |
||||
|
} |
||||
|
|
||||
|
@ExtApiStatu(name = "", group = "项目卡信息", order = 3, minWidth = "33.3%") |
||||
|
public ProjExtInfoCard showProjExtInfoCard() { |
||||
|
return cxt.projExtInfoCard; |
||||
|
} |
||||
|
|
||||
|
@ExtApiStatu(name = "", group = "上下文", order = 4, minWidth = "33.3%") |
||||
|
public Object showConsumableInfo() { |
||||
|
return Map.<String, Object>of( |
||||
|
"耗材位置", String.format("%s-%d", cxt.consumableGroup, cxt.consumablePosOff), |
||||
|
"孵育盘位置", cxt.incubatorPos, |
||||
|
"取样位置", cxt.samplePos, |
||||
|
"样本信息是否初始化", cxt.isInit |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@ExtApiStatu(name = "", group = "状态", order = 5, minWidth = "33.3%") |
||||
|
public State showState() { |
||||
|
return state; |
||||
|
} |
||||
|
|
||||
|
@ExtApiStatu(name = "", group = "结果", order = 6, minWidth = "33.3%") |
||||
|
public List<ReactionResult> showResults() { |
||||
|
return cxt.results; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
Integer tippos = 0; |
||||
|
|
||||
|
void takeTip() throws AppException { |
||||
|
Boolean takeTip = false; |
||||
|
for (int i = 0; i < 10; i++) { |
||||
|
tippos = tippos % 120; |
||||
|
takeTip = hbotMoveExCtrlService.takeTipNoCheck(TipGroup.TipG1, tippos); |
||||
|
if (takeTip) { |
||||
|
break; |
||||
|
} |
||||
|
tippos++; |
||||
|
} |
||||
|
if (!takeTip) { |
||||
|
throw AppException.ofAECodeError("取Tip失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void clearDevice() throws AppException { |
||||
|
optScanModuleCtrlService.dropPlate(); |
||||
|
optScanModuleCtrlService.pullPlate(IncubatorPos.SPACE01); |
||||
|
optScanModuleCtrlService.dropPlate(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void prepareReactionPlate() throws AppException { |
||||
|
plateBoxCtrlService.pushPlateQuick(cxt.consumableGroup, cxt.incubatorPos); |
||||
|
} |
||||
|
|
||||
|
void procesSample() throws AppException { |
||||
|
liquidOperationCtrlService.setProjContext(cxt.projBuildinInfo, cxt.projExtInfoCard); |
||||
|
if (!hbotMoveExCtrlService.isHasTip()) |
||||
|
takeTip(); |
||||
|
if (cxt.projBuildinInfo.reactionFlowType.equals(A8kReactionFlowType.SampleAndBS)) { |
||||
|
//param 小瓶缓冲液位置 |
||||
|
var preReactionPos = new PreReactionPos(ConsumableType.SmallBottleBuffer, cxt.consumableGroup, cxt.consumablePosOff); |
||||
|
//param 取样量 |
||||
|
Integer sampleVol = ProjInfoReader.getSampleVol(cxt.projBuildinInfo, cxt.projExtInfoCard, cxt.sampleInfo.bloodType); |
||||
|
|
||||
|
|
||||
|
//action ->刺破 |
||||
|
liquidOperationCtrlService.pirceLittleBuffer(preReactionPos); |
||||
|
//action ->取样 |
||||
|
liquidOperationCtrlService.takeSample(cxt.samplePos, preReactionPos, sampleVol); |
||||
|
//action ->孵育盘移动到吐液位置 |
||||
|
turnableMoveCtrlService.trunableMoveToDropLiquidPos(cxt.incubatorPos); // |
||||
|
//action ->取反应液到反应板上 |
||||
|
liquidOperationCtrlService.takePreReactionLiquidToLiquid(preReactionPos); // |
||||
|
} else if (cxt.projBuildinInfo.reactionFlowType.equals(A8kReactionFlowType.SampleAndBSAndProbeSubstance)) { |
||||
|
//param 探测物位置 |
||||
|
var preReactionPos = new PreReactionPos(ConsumableType.ProbeSubstance, cxt.consumableGroup, cxt.consumablePosOff); |
||||
|
//param 取样量 |
||||
|
Integer sampleVol = ProjInfoReader.getSampleVol(cxt.projBuildinInfo, cxt.projExtInfoCard, cxt.sampleInfo.bloodType); |
||||
|
|
||||
|
//action ->取大瓶缓冲液到探测物质 |
||||
|
liquidOperationCtrlService.takeLargeBottleBufferLiquidToProbeSubstance( |
||||
|
LargeBufferPos.of(cxt.consumableGroup), preReactionPos, cxt.projBuildinInfo.bigBufferSampleUl); |
||||
|
|
||||
|
//action ->取样品 |
||||
|
liquidOperationCtrlService.takeSample(cxt.samplePos, preReactionPos, sampleVol); |
||||
|
//action ->孵育盘移动到吐液位置 |
||||
|
turnableMoveCtrlService.trunableMoveToDropLiquidPos(cxt.incubatorPos); // |
||||
|
//action ->取反应液到反应板上 |
||||
|
liquidOperationCtrlService.takePreReactionLiquidToLiquid(preReactionPos); // |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void incubate() throws AppException { |
||||
|
//等待孵育完成 |
||||
|
state.incubateRemainTime = cxt.projBuildinInfo.reactionPlateIncubationTimeMin * 60; |
||||
|
while (state.incubateRemainTime > 0) { |
||||
|
state.incubateRemainTime -= 1; |
||||
|
OS.forceSleep(1000); |
||||
|
} |
||||
|
frontEndMessageBoxAndEventMgr.showInfo("孵育完成"); |
||||
|
} |
||||
|
|
||||
|
void pullAndScan() throws AppException { |
||||
|
optScanModuleCtrlService.pullPlate(cxt.incubatorPos); |
||||
|
ProjInfo projInfo = new ProjInfo(); |
||||
|
projInfo.buildIn = cxt.projBuildinInfo; |
||||
|
projInfo.ext = cxt.projExtInfoCard; |
||||
|
|
||||
|
List<OptScanResult> optScanResults = new ArrayList<>(); |
||||
|
for (int i = 0; i < cxt.projBuildinInfo.subProjNum; i++) { |
||||
|
var optScanResult = optScanModuleCtrlService.optScan(cxt.projBuildinInfo, i); |
||||
|
|
||||
|
ReactionResult result = A8kReactionResultComputer.optComputeResult(cxt.sampleInfo, projInfo, i, optScanResult.analysResult); |
||||
|
cxt.results.add(result); |
||||
|
optScanResults.add(optScanResult); |
||||
|
} |
||||
|
reactionRecordMgrService.addRecord(cxt.sampleInfo, projInfo, optScanResults, cxt.results); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
public void initSampleInfo() throws AppException { |
||||
|
cxt.sampleInfo.sampleId = ZDateUtils.toID(new Date()); |
||||
|
cxt.sampleInfo.userid = cxt.sampleInfo.sampleId; |
||||
|
cxt.sampleInfo.sampleBarcode = cxt.sampleInfo.sampleId; |
||||
|
cxt.sampleInfo.bloodType = BloodType.SERUM_OR_PLASMA; |
||||
|
cxt.sampleInfo.isHighTube = false; |
||||
|
cxt.sampleInfo.isEmergency = true; |
||||
|
|
||||
|
|
||||
|
cxt.projExtInfoCard = projIdCardInfoMgrService.getMountedProjInfoCard(); |
||||
|
Assert.notNull(cxt.projExtInfoCard, "请插入项目卡"); |
||||
|
cxt.projBuildinInfo = projInfoMgrService.getProjBuildInInfo(cxt.projExtInfoCard.projId); |
||||
|
cxt.isInit = true; |
||||
|
|
||||
|
cxt.incubatorPos = IncubatorPos.SPACE01; |
||||
|
cxt.consumableGroup = ConsumableGroup.CG1; |
||||
|
cxt.consumablePosOff = 0; |
||||
|
} |
||||
|
|
||||
|
public void startProcessSample(Boolean scanOnly) throws AppException { |
||||
|
initSampleInfo(); |
||||
|
clearDevice(); |
||||
|
frontEndMessageBoxAndEventMgr.showInfo("反应板准备"); |
||||
|
prepareReactionPlate(); |
||||
|
if (!scanOnly) { |
||||
|
frontEndMessageBoxAndEventMgr.showInfo("样本处理"); |
||||
|
procesSample(); |
||||
|
frontEndMessageBoxAndEventMgr.showInfo("孵育"); |
||||
|
incubate(); |
||||
|
} |
||||
|
frontEndMessageBoxAndEventMgr.showInfo("扫描"); |
||||
|
pullAndScan(); |
||||
|
frontEndMessageBoxAndEventMgr.showInfo("丢板"); |
||||
|
optScanModuleCtrlService.dropPlate(); |
||||
|
frontEndMessageBoxAndEventMgr.showInfo("结束"); |
||||
|
} |
||||
|
|
||||
|
public void sampleAndIncubateAndScan() throws AppException { |
||||
|
startProcessSample(false); |
||||
|
} |
||||
|
|
||||
|
public void scanOnly(Integer scanTimes) throws AppException { |
||||
|
for (int i = 0; i < scanTimes; i++) { |
||||
|
startProcessSample(true); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@Resource |
||||
|
ExtApiPageMgr extApiPageMgr; |
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init() { |
||||
|
var page = extApiPageMgr.newPage(this); |
||||
|
page.addFunction("取样.孵育.扫描", this::sampleAndIncubateAndScan); |
||||
|
page.addFunction("只扫描", this::scanOnly); |
||||
|
extApiPageMgr.addPage(page); |
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue