From 4a7a8029d40d60060c19722056516a7e6ae65419 Mon Sep 17 00:00:00 2001 From: zhaohe Date: Sun, 6 Oct 2024 17:00:53 +0800 Subject: [PATCH] update --- README.md | 27 ++- .../extapi/pagecontrol/ExtApiTabConfig.java | 1 - src/main/java/a8k/dbservice/type/SampleRecord.java | 1 + .../a8k/hardware/type/a8kcanprotocol/A8kEcode.java | 78 +------- .../a8k/service/appdata/AppProjInfoMgrService.java | 2 +- .../a8k/service/appdata/AppSampleMgrService.java | 84 --------- .../service/appdata/AppSampleRecordMgrService.java | 105 +++++++++++ .../appdevicectrl/AppConsumablesMgrService.java | 206 +++++++++++++-------- .../AppEmergencySamplePosStateMgrService.java | 50 +++-- .../appdevicectrl/action/DO_EJECT_TUBEHOLDER.java | 57 ------ .../appdevicectrl/action/base/A8kStepAction.java | 6 + .../action/mainflow/DO_EJECT_TUBEHOLDER.java | 58 ++++++ .../mainflow/SEQ1_ENTER_TUBEHOLDER_AND_SCAN.java | 38 ++-- .../mainflow/SEQ2_SWITCH_TO_THE_NEXT_TUBE.java | 103 +++++++---- .../SEQ3_CHECK_THE_QUANTITY_OF_CONSUMABLES.java | 60 ++++-- .../a8k/service/appstate/AppA8kGStateService.java | 28 +-- .../AppSampleProcessContextMgrService.java | 46 +++++ .../appstate/type/EmergencyPosRunState.java | 19 -- .../service/appstate/type/EmergencyTubePos.java | 8 + .../a8k/service/appstate/type/IncubationPlate.java | 10 + src/main/java/a8k/service/appstate/type/Tube.java | 8 +- .../java/a8k/service/appstate/type/TubeHolder.java | 15 +- .../service/appstate/type/TubeProcessContext.java | 21 +++ .../appstate/type/state/EmergencySampleState.java | 8 - .../appstate/type/state/TubeHolderState.java | 1 - .../a8k/service/appstate/type/state/TubeState.java | 6 +- .../devicedriver/ctrl/ConsumablesScanCtrl.java | 54 ++++-- 27 files changed, 640 insertions(+), 460 deletions(-) delete mode 100644 src/main/java/a8k/service/appdata/AppSampleMgrService.java create mode 100644 src/main/java/a8k/service/appdata/AppSampleRecordMgrService.java delete mode 100644 src/main/java/a8k/service/appdevicectrl/action/DO_EJECT_TUBEHOLDER.java create mode 100644 src/main/java/a8k/service/appdevicectrl/action/mainflow/DO_EJECT_TUBEHOLDER.java create mode 100644 src/main/java/a8k/service/appstate/AppSampleProcessContextMgrService.java delete mode 100644 src/main/java/a8k/service/appstate/type/EmergencyPosRunState.java create mode 100644 src/main/java/a8k/service/appstate/type/EmergencyTubePos.java create mode 100644 src/main/java/a8k/service/appstate/type/TubeProcessContext.java delete mode 100644 src/main/java/a8k/service/appstate/type/state/EmergencySampleState.java diff --git a/README.md b/README.md index 7bedd76..79df0cc 100644 --- a/README.md +++ b/README.md @@ -149,10 +149,14 @@ TODO: ``` 动作: 入料并扫描 - 将下一个试管移动到预处理位 + 准备下一个样本 + 条件: 当前正在处理的样本处理完成 && + 急诊位Pending | 还有剩余试管未处理 + + - 核对资源是否可以被处理 + 样本处理 BEFORE_PROCESS 预处理A(脱帽,摇匀) BEFORE_PROCESS 预处理B(hbot取tip头,移动到待机位) BEFORE_PROCESS 预处理C(推出反应板夹) @@ -160,11 +164,14 @@ TODO: PROCESS 处理(取样,处理,滴定) AFTER_PROCESS 后处理 - 出料 + 将反应板推出到光学扫描位 光学扫描 + + + 代码规范 1. 什么样的检查写在动作中? 需要进行报错处理的检查写在步骤中 @@ -185,4 +192,18 @@ TODO: 5. 支持吸空检测。 6. 支持反应板夹类型检测。 +``` + + +``` + +TODO: + 1. 如果当前板夹仓对应位置的耗材批次码没有发生变化,则耗材量不重新初始化。 + 2. tip头只有在第一次扫描时,才会初始化其数量是满的。 + + + + + + ``` \ No newline at end of file diff --git a/src/main/java/a8k/controler/extapi/pagecontrol/ExtApiTabConfig.java b/src/main/java/a8k/controler/extapi/pagecontrol/ExtApiTabConfig.java index c978b85..40887f3 100644 --- a/src/main/java/a8k/controler/extapi/pagecontrol/ExtApiTabConfig.java +++ b/src/main/java/a8k/controler/extapi/pagecontrol/ExtApiTabConfig.java @@ -10,7 +10,6 @@ public enum ExtApiTabConfig { AppUserMgrService("应用数据.用户管理", true), //Ok AppSettingsMgr("应用数据.设备配置管理", true), //OK - AppProjectItemMgrService("应用数据.ID卡状态管理", true), //OK AppProjInfoMgrService("应用数据.项目信息管理", true), //OK AppReactionResultMgrService("应用数据.反应结果管理", true), //OK AppSampleMgrService("应用数据.样本管理", true), //OK diff --git a/src/main/java/a8k/dbservice/type/SampleRecord.java b/src/main/java/a8k/dbservice/type/SampleRecord.java index efbf972..1f281c1 100644 --- a/src/main/java/a8k/dbservice/type/SampleRecord.java +++ b/src/main/java/a8k/dbservice/type/SampleRecord.java @@ -14,6 +14,7 @@ public class SampleRecord { public String sampleid; // generated by system , year%100+month+day+时分 241230_1203_01 public Date date; public BloodType bloodType = BloodType.WHOLE_BLOOD; //血液类型 + public Boolean isEmergency = false; //是否急诊 public String sampleBarcode = ""; //用于请求用户信息的条码ID public String userid = ""; //用户输入的样本ID,不做逻辑,只做展示 public List projIndex = new ArrayList<>(); //项目代码,逗号分隔 diff --git a/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java b/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java index 6ba0ae1..9550482 100644 --- a/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java +++ b/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java @@ -57,6 +57,7 @@ public enum A8kEcode { TubeHolderSettingNotFound(139),//试管架设置未找到 TubeHolderTypeIsNotSupport(140),//试管架类型不支持 EmergencySampleIsProcessing(141),//急诊样本正在处理中 + ConsumeNotEnough(142),//耗材不足 /** * 特殊服务错误码 @@ -66,164 +67,87 @@ public enum A8kEcode { * 其他 */ ActionReactorService_breakByUsr(900), - OS_threadInterrupt(901),//Sleep被中断 - TestScrip_deviceIsBusy(902), - CheckPoint_checkFail(903), //检查点检查失败 // // LowBoard // HardwareErrorStart(1000), - BoardCommonError(1001), - ParamOutOfRange(1102), - CmdNotSupport(1103), - DeviceIsBusy(1104), - DeviceIsOffline(1105), - Overtime(1106), - Noack(1107), - Errorack(1108), - DeviceOffline(1109), - SubdeviceOvertime(1111), - BufferNotEnough(1112), - CmdParamNumError(1114), - CheckcodeIsError(1115), - IllegalOperation(1116), - ActionOvertime(1117), - ModuleOpeationBreakByUser(1202), - ModuleNotFindReg(1207), - XymotorXFindZeroEdgeFail(1306), - XymotorYFindZeroEdgeFail(1307), - XymotorNotEnable(1308), - XymotorTargetPosOutofRange(1309), - XymotorNotMoveToZero(1310), - PipetteErrorNoError(1400), - PipetteErrorInitFail(1401), - PipetteErrorInvalidCmd(1402), - PipetteErrorInvalidArg(1403), - PipetteErrorPressureSensorError(1404), - PipetteErrorOverPressure(1405), - PipetteErrorLldError(1406), - PipetteErrorDeviceNotInit(1407), - PipetteErrorTipPopError(1408), - PipetteErrorPumpOverload(1409), - PipetteErrorTipDrop(1410), - PipetteErrorCanBusError(1411), - PipetteErrorInvalidChecksum(1412), - PipetteErrorEepromError(1413), - PipetteErrorCmdBufferEmpty(1414), - PipetteErrorCmdBufferOverflow(1415), - PipetteErrorTipBlock(1416), - PipetteErrorAirSuction(1417), - PipetteErrorBubble(1418), - PipetteErrorVolumeError(1419), - PipetteErrorTipAlreadyLoad(1420), - PipetteErrorTipLoadFail(1421), - PipetteErrorUninited(1501), - PipetteErrorNotLldPrepare(1502), - PipetteErrorTipisloadWhenLldPrepare(1500), - PipetteErrorPumpLoadValIsNotEmpty(1503), - StepMotorNotFoundZeroPoint(1600), - StepMotorNotGoZero(1601), - StepMotorOverTemperature(1602), - StepMotorOverVoltage(1603), - StepMotorRunOvertime(1604), - StepMotorNotEnable(1605), - StepMotorIoindexOutOfRange(1606), - StepMotorSubicReset(1607), - StepMotorDrvErr(1608), - StepMotorUvCp(1609), - StepMotorNotFoundPointEdge(1610), - StepMotorLostStep(1611), - StepMotorNotMoveToZero(1612), - StepMotorOt(1613), - StepMotorOtpw(1614), - StepMotorS2ga(1615), - StepMotorS2gb(1616), - StepMotorOla(1617), - StepMotorOlb(1618), - MiniServoNotEnable(1700), - MiniServoModeNotSupport(1701), - FanHardwareFault(1800), - WaterCoolingFanError(1900), - WaterCoolingTemperatureSensorError(1902), - WaterCoolingPumpIsError(1903), - WaterCoolingPelterIsError(1904), ; diff --git a/src/main/java/a8k/service/appdata/AppProjInfoMgrService.java b/src/main/java/a8k/service/appdata/AppProjInfoMgrService.java index f855701..26f63f1 100644 --- a/src/main/java/a8k/service/appdata/AppProjInfoMgrService.java +++ b/src/main/java/a8k/service/appdata/AppProjInfoMgrService.java @@ -26,7 +26,7 @@ import org.springframework.stereotype.Component; import java.util.List; @Component -@ExtApiTab(cfg = ExtApiTabConfig.AppProjectItemMgrService) +@ExtApiTab(cfg = ExtApiTabConfig.AppProjInfoMgrService) public class AppProjInfoMgrService implements AppEventListener { static Logger logger = org.slf4j.LoggerFactory.getLogger(AppProjInfoMgrService.class); diff --git a/src/main/java/a8k/service/appdata/AppSampleMgrService.java b/src/main/java/a8k/service/appdata/AppSampleMgrService.java deleted file mode 100644 index 1c04e70..0000000 --- a/src/main/java/a8k/service/appdata/AppSampleMgrService.java +++ /dev/null @@ -1,84 +0,0 @@ -package a8k.service.appdata; - -import a8k.controler.extapi.pagecontrol.ExtApiTabConfig; -import a8k.controler.extapi.utils.ExtApiFn; -import a8k.controler.extapi.utils.ExtApiTab; -import a8k.dbservice.SampleRecordDBService; -import a8k.dbservice.type.SampleRecord; -import a8k.service.appstate.type.Tube; -import a8k.type.type.BloodType; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Component; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; - -@Component -@ExtApiTab(cfg = ExtApiTabConfig.AppSampleMgrService) -public class AppSampleMgrService { - - @Resource - SampleRecordDBService sampleRecordDBService; - - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - @PostConstruct - public void init() { - } - - String generateSampleId(Date date, Integer tubePos) { - String sampleid = ""; - SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd_HHmmss"); - sampleid = String.format("%s_%s", sdf.format(date), tubePos); - return sampleid; - } - - @ExtApiFn(name = "addSampleRecordExtApi") - public SampleRecord addSampleRecordExtApi(Integer tuebPos, BloodType bloodType, String sampleBarcode, String userid, String projIndex) { - return addSampleRecord(new Date(), tuebPos, bloodType, sampleBarcode, userid, projIndex); - } - - @ExtApiFn(name = "getAllSampleRecordsExtApi") - public List getAllSampleRecords() { - return sampleRecordDBService.getAll(); - } - - public SampleRecord addSampleRecord(Date intertime, Integer tuebPos, BloodType bloodType, String sampleBarcode, String userid, String projIndex) { - SampleRecord record = new SampleRecord(); - record.bloodType = bloodType; - record.sampleBarcode = sampleBarcode; - record.userid = userid; - record.date = intertime; - record.sampleid = generateSampleId(intertime, tuebPos); - for (String s : projIndex.split(",")) { - record.projIndex.add(Integer.parseInt(s)); - } - sampleRecordDBService.add(record); - return record; - } - - public void addSampleRecord(Tube[] state) { - Date intertime = new Date(); - for (int i = 0; i < state.length; i++) { - if (state[i] == null) { - continue; - } - if (!state[i].isTubeExist) { - continue; - } - SampleRecord record = new SampleRecord(); - record.bloodType = state[i].bloodType; - record.sampleBarcode = state[i].sampleBarcode; - record.userid = state[i].userid; - record.date = intertime; - record.sampleid = generateSampleId(intertime, i); - record.projIndex = state[i].projIndex; - state[i].sampleid = record.sampleid; - sampleRecordDBService.add(record); - } - } - - -} diff --git a/src/main/java/a8k/service/appdata/AppSampleRecordMgrService.java b/src/main/java/a8k/service/appdata/AppSampleRecordMgrService.java new file mode 100644 index 0000000..cf057e4 --- /dev/null +++ b/src/main/java/a8k/service/appdata/AppSampleRecordMgrService.java @@ -0,0 +1,105 @@ +package a8k.service.appdata; + +import a8k.controler.extapi.pagecontrol.ExtApiTabConfig; +import a8k.controler.extapi.utils.ExtApiFn; +import a8k.controler.extapi.utils.ExtApiTab; +import a8k.dbservice.SampleRecordDBService; +import a8k.dbservice.type.SampleRecord; +import a8k.service.appstate.type.Tube; +import a8k.service.appstate.type.state.TubeState; +import a8k.type.type.BloodType; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +@Component +@ExtApiTab(cfg = ExtApiTabConfig.AppSampleMgrService) +public class AppSampleRecordMgrService { + + @Resource + SampleRecordDBService sampleRecordDBService; + + // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + @PostConstruct + public void init() { + } + + String generateSampleId(Date date, Integer tubePos) { + String sampleid = ""; + SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd_HHmmss"); + sampleid = String.format("%s_%s", sdf.format(date), tubePos + 1); + if (tubePos == -1) { + sampleid = String.format("%s_%s", sdf.format(date), "E"); + } + return sampleid; + } + + @ExtApiFn(name = "addSampleRecordExtApi") + public SampleRecord addSampleRecordExtApi(Integer tuebPos, BloodType bloodType, String sampleBarcode, String userid, String projIndex) { + return addSampleRecord(new Date(), tuebPos, bloodType, sampleBarcode, userid, projIndex); + } + + @ExtApiFn(name = "getAllSampleRecordsExtApi") + public List getAllSampleRecords() { + return sampleRecordDBService.getAll(); + } + + public SampleRecord addSampleRecord(Date intertime, Integer tuebPos, BloodType bloodType, String sampleBarcode, String userid, String projIndex) { + SampleRecord record = new SampleRecord(); + record.bloodType = bloodType; + record.sampleBarcode = sampleBarcode; + record.userid = userid; + record.date = intertime; + record.sampleid = generateSampleId(intertime, tuebPos); + for (String s : projIndex.split(",")) { + record.projIndex.add(Integer.parseInt(s)); + } + sampleRecordDBService.add(record); + return record; + } + + public void addSampleRecord(Tube[] state) { + Date intertime = new Date(); + for (int i = 0; i < state.length; i++) { + if (state[i] == null) { + continue; + } + if (state[i].state.equals(TubeState.EMPTY)) { + continue; + } + SampleRecord record = new SampleRecord(); + record.bloodType = state[i].bloodType; + record.sampleBarcode = state[i].sampleBarcode; + record.userid = state[i].userid; + record.date = intertime; + record.isEmergency = state[i].isEmergency; + record.sampleid = generateSampleId(intertime, i); + record.projIndex = state[i].projIndex; + state[i].sampleid = record.sampleid; + sampleRecordDBService.add(record); + } + } + + public void addEmergencySampleRecord(Tube state) { + Date intertime = new Date(); + SampleRecord record = new SampleRecord(); + state.isEmergency = true; + + record.bloodType = state.bloodType; + record.sampleBarcode = state.sampleBarcode; + record.userid = state.userid; + record.date = intertime; + record.isEmergency = true; + record.sampleid = generateSampleId(intertime, -1); + record.projIndex = state.projIndex; + state.sampleid = record.sampleid; + sampleRecordDBService.add(record); + } + + +} diff --git a/src/main/java/a8k/service/appdevicectrl/AppConsumablesMgrService.java b/src/main/java/a8k/service/appdevicectrl/AppConsumablesMgrService.java index f9c5a1d..8ec80f9 100644 --- a/src/main/java/a8k/service/appdevicectrl/AppConsumablesMgrService.java +++ b/src/main/java/a8k/service/appdevicectrl/AppConsumablesMgrService.java @@ -36,10 +36,6 @@ public class AppConsumablesMgrService { @Resource ConsumablesScanCtrl scanCtrlService; - public ConsumablesScanCtrl.ConsumablesScanRawResult doScanConsumablesAction() throws AppException { - return scanCtrlService.doScanConsumablesAction(); - } - /** * 解析扫描结果,返回耗材扫描结果 * @@ -47,22 +43,22 @@ public class AppConsumablesMgrService { * @param rawResult 原始扫描结果 * @return 耗材扫描结果 */ - ConsumablesScanResult parseScanResult(Integer ch, ConsumablesScanCtrl.ConsumablesScanRawResult rawResult) throws AppException { + ConsumablesScanResult parseScanResult(Integer ch, ConsumablesScanCtrl.OneChResult rawResult) throws AppException { ConsumablesScanResult ret = new ConsumablesScanResult(); ret.chNum = ch; - if (rawResult.larBSScanResult[ch] == null && rawResult.littBSScanResult[ch] == null && rawResult.PBScanResult[ch] == null) { + if (rawResult.larBSScanResult == null && rawResult.littBSScanResult == null && rawResult.PBScanResult == null) { ret.state = ScanResultState.Empty; return ret; } - if (rawResult.PBScanResult[ch] == null) { + if (rawResult.PBScanResult == null) { ret.state = ScanResultState.LostReactionPlate; return ret; } //解析板夹二维码 - ReactionPlate2DCode rp2dcode = ReactionPlate2DCodeParser.parse(rawResult.PBScanResult[ch]); + ReactionPlate2DCode rp2dcode = ReactionPlate2DCodeParser.parse(rawResult.PBScanResult); //检查耗材是否过期 if (rp2dcode.expDate.before(new Date())) { @@ -87,13 +83,13 @@ public class AppConsumablesMgrService { if (reactionType.equals(A8kReactionFlowType.ReactionWithLittBS)) { //校验小瓶缓冲液,小瓶缓冲液+样本 - if (rawResult.littBSScanResult[ch] == null) { + if (rawResult.littBSScanResult == null) { ret.state = ScanResultState.LostLittSB; return ret; } } else if (reactionType.equals(A8kReactionFlowType.ReactionWithLarBsAndDetection)) { // 校验大瓶缓冲液,大瓶缓冲液+小瓶缓冲液+样本 - if (rawResult.larBSScanResult[ch] == null) { + if (rawResult.larBSScanResult == null) { ret.state = ScanResultState.LostLarBS; return ret; } @@ -106,77 +102,84 @@ public class AppConsumablesMgrService { return ret; } + void LoadingConsumables(Integer ch, ConsumablesScanResult result) { + var cState = gstate.getConsumableState(); + assert ch.equals(result.chNum); + if (result.state != ScanResultState.PASS) { + return; + } - //扫描耗材 - public Map doScanConsumables() throws AppException { - if (!gstate.isDeviceInited()) { - throw new AppException(A8kEcode.DeviceNotInited.index); + A8kIdCardInfo a8kIdCardInfo = appProjMgr.getA8kIdCardInfoByLotId(result.lotId); + A8kReactionFlowType reactionType = appProjMgr.getA8kReactionFlowTypeByProjIndex(result.projIndex); + assert a8kIdCardInfo != null; + assert reactionType != null; + + cState.reactionPlateGroup[ch] = new ReactionPlateGroup(// + result.projIndex, // + a8kIdCardInfo.projName, // + result.lotId, // + a8kIdCardInfo.color, // + EachConsumableNum); + cState.reactionPlateGroup[ch].editable = true; + + if (reactionType.equals(A8kReactionFlowType.ReactionWithLittBS)) { + cState.littBSGroup[ch] = new LittBSGroup(// + result.projIndex, // + a8kIdCardInfo.projName, // + result.lotId, // + a8kIdCardInfo.color, // + EachConsumableNum); + cState.littBSGroup[ch].editable = true; + + cState.larBSGroup[ch] = new LarBSGroup(); + cState.larBSGroup[ch].editable = false; + } else if (reactionType.equals(A8kReactionFlowType.ReactionWithLarBsAndDetection)) { + cState.littBSGroup[ch] = new LittBSGroup(// + result.projIndex, // + a8kIdCardInfo.projName, // + result.lotId, // + a8kIdCardInfo.color, // + EachConsumableNum); + cState.littBSGroup[ch].editable = true; + + cState.larBSGroup[ch] = new LarBSGroup(// + result.projIndex, // + a8kIdCardInfo.projName, // + result.lotId, // + a8kIdCardInfo.color, // + EachConsumableNum); + cState.larBSGroup[ch].editable = true; + + } else { + throw new RuntimeException("未知的反应流程类型"); } - gstate.setConsumableState(null); + } - List scanResult = new java.util.ArrayList<>(); - //执行扫描耗材动作 - var scanRawResult = doScanConsumablesAction(); + /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * EXT + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + @ExtApiFn(name = "扫描耗材(阻塞接口)", order = 1) + public Map scanConsumables() throws AppException { + if (!gstate.isDeviceInited()) { + throw new AppException(A8kEcode.DeviceNotInited.index); + } + List scanResult = new java.util.ArrayList<>(); + //执行扫描耗材动作 + var scanRawResult = scanCtrlService.doScanConsumablesAction(); //解析扫描结果 for (int i = 0; i < 6; i++) { - var result = parseScanResult(i, scanRawResult); + var result = parseScanResult(i, scanRawResult.ch[i]); scanResult.add(result); } - var cState = new ConsumableState(); - for (int i = 0; i < cState.tipGroup.length; i++) { - cState.tipGroup[i].tipNum = 120; - } - + var cState = gstate.getConsumableState(); + //加载耗材 for (int i = 0; i < cState.reactionPlateGroup.length; i++) { if (scanResult.get(i).state == ScanResultState.PASS) { - A8kIdCardInfo a8kIdCardInfo = appProjMgr.getA8kIdCardInfoByLotId(scanResult.get(i).lotId); - A8kReactionFlowType reactionType = appProjMgr.getA8kReactionFlowTypeByProjIndex(scanResult.get(i).projIndex); - assert a8kIdCardInfo != null; - assert reactionType != null; - - cState.reactionPlateGroup[i] = new ReactionPlateGroup(// - scanResult.get(i).projIndex, // - a8kIdCardInfo.projName, // - scanResult.get(i).lotId, // - a8kIdCardInfo.color, // - EachConsumableNum); - cState.reactionPlateGroup[i].editable = true; - - if (reactionType.equals(A8kReactionFlowType.ReactionWithLittBS)) { - cState.littBSGroup[i] = new LittBSGroup(// - scanResult.get(i).projIndex, // - a8kIdCardInfo.projName, // - scanResult.get(i).lotId, // - a8kIdCardInfo.color, // - EachConsumableNum); - cState.littBSGroup[i].editable = true; - - cState.larBSGroup[i] = new LarBSGroup(); - cState.larBSGroup[i].editable = false; - } else if (reactionType.equals(A8kReactionFlowType.ReactionWithLarBsAndDetection)) { - cState.littBSGroup[i] = new LittBSGroup(// - scanResult.get(i).projIndex, // - a8kIdCardInfo.projName, // - scanResult.get(i).lotId, // - a8kIdCardInfo.color, // - EachConsumableNum); - cState.littBSGroup[i].editable = true; - - cState.larBSGroup[i] = new LarBSGroup(// - scanResult.get(i).projIndex, // - a8kIdCardInfo.projName, // - scanResult.get(i).lotId, // - a8kIdCardInfo.color, // - EachConsumableNum); - cState.larBSGroup[i].editable = true; - - } else { - throw new RuntimeException("未知的反应流程类型"); - } + LoadingConsumables(i, scanResult.get(i)); } } @@ -184,17 +187,39 @@ public class AppConsumablesMgrService { ret.put("scanResult", scanResult); ret.put("scanRawResult", scanRawResult); ret.put("consumableState", cState); - gstate.setConsumableState(cState); return ret; } - /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * EXT - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ - - @ExtApiFn(name = "扫描耗材(阻塞接口)", order = 1) - public Map scanConsumables() throws AppException { - return doScanConsumables(); + @ExtApiFn(name = "扫描某一个通道耗材(阻塞接口)", order = 1) + public Map scanOneChConsumables(Integer chNum) throws AppException { + if (!gstate.isDeviceInited()) { + throw new AppException(A8kEcode.DeviceNotInited.index); + } + List scanResult = new java.util.ArrayList<>(); + // var scanRawResult = doScanOneCh(Integer ch); + // + // + // //执行扫描耗材动作 + // var scanRawResult = parseScanResult(chNum, scanRawResult.ch[chNum]); + //解析扫描结果 + // for (int i = 0; i < 6; i++) { + // var result = parseScanResult(i, scanRawResult.ch[i]); + // scanResult.add(result); + // } + // + // var cState = gstate.getConsumableState(); + // //加载耗材 + // for (int i = 0; i < cState.reactionPlateGroup.length; i++) { + // if (scanResult.get(i).state == ScanResultState.PASS) { + // LoadingConsumables(i, scanResult.get(i)); + // } + // } + // + // Map ret = new java.util.HashMap<>(); + // ret.put("scanResult", scanResult); + // ret.put("scanRawResult", scanRawResult); + // ret.put("consumableState", cState); + return null; } @@ -214,4 +239,33 @@ public class AppConsumablesMgrService { cState.larBSGroup[ch].num = num; } + synchronized public void setTipConsumableNum(Integer group, Integer num) { + var cState = gstate.getConsumableState(); + assert cState != null; + cState.tipGroup[group].tipNum = num; + } + + synchronized public Integer getConsumableNum(Integer projIndex) { + Integer total = 0; + var cState = gstate.getConsumableState(); + for (int i = 0; i < cState.reactionPlateGroup.length; i++) { + if (cState.reactionPlateGroup[i].projIndex.equals(projIndex)) { + total += cState.reactionPlateGroup[i].num; + } + } + return total; + } + + synchronized public Boolean isHasEnoughConsumables(List projIndex) { + // + //只检查反应板的数量即可 + for (Integer index : projIndex) { + Integer total = getConsumableNum(index); + if (total < 1) { + return false; + } + } + return false; + } + } diff --git a/src/main/java/a8k/service/appdevicectrl/AppEmergencySamplePosStateMgrService.java b/src/main/java/a8k/service/appdevicectrl/AppEmergencySamplePosStateMgrService.java index 862346a..99ebb9c 100644 --- a/src/main/java/a8k/service/appdevicectrl/AppEmergencySamplePosStateMgrService.java +++ b/src/main/java/a8k/service/appdevicectrl/AppEmergencySamplePosStateMgrService.java @@ -5,9 +5,12 @@ import a8k.controler.extapi.utils.EnginnerPageActionParam; import a8k.controler.extapi.utils.ExtApiFn; import a8k.controler.extapi.utils.ExtApiTab; import a8k.hardware.type.a8kcanprotocol.A8kEcode; +import a8k.service.appdata.AppSampleRecordMgrService; import a8k.service.appstate.AppA8kGStateService; -import a8k.service.appstate.type.EmergencyPosRunState; -import a8k.service.appstate.type.state.EmergencySampleState; +import a8k.service.appstate.AppSampleProcessContextMgrService; +import a8k.service.appstate.type.EmergencyTubePos; +import a8k.service.appstate.type.Tube; +import a8k.service.appstate.type.state.TubeState; import a8k.type.exception.AppException; import a8k.type.type.BloodType; import jakarta.annotation.Resource; @@ -20,22 +23,11 @@ public class AppEmergencySamplePosStateMgrService { @Resource AppA8kGStateService gstate; - /* - * 状态变化 - * - * 初始时: - * getEmergencyPosRunState() -> state = IDLE - * - * 提交样本配置后 - * getEmergencySampleSetting() -> state = PENDING - * - * 提交样本配置,且机器开始处理急诊样本时候 - * getEmergencyPosRunState() -> state = PROCESSING - * - * 机器处理完急诊样本后 - * getEmergencyPosRunState() -> state = FINISHED - */ + @Resource + AppSampleRecordMgrService sampleRecordMgrService; + @Resource + AppSampleProcessContextMgrService appSampleProcessContextMgrService; /** * 提交紧急样本设置 @@ -49,24 +41,28 @@ public class AppEmergencySamplePosStateMgrService { @ExtApiFn(name = "提交紧急样本设置", group = "紧急样本设置") public void commitEmergencySampleSetting(String userid, String sampleBarcode, BloodType bloodType,// @EnginnerPageActionParam(name = "逗号分割项目列表(例子1,2,3)") String projIndexList) throws AppException { - EmergencyPosRunState state = gstate.getEmergencyPosRunState(); - if (state.state.equals(EmergencySampleState.IDLE) || state.state.equals(EmergencySampleState.FINISHED)) { - state.userid = userid; - state.bloodType = bloodType; - state.sampleBarcode = sampleBarcode; - state.projIndex.clear(); + EmergencyTubePos emergencyTubePos = gstate.getEmergencyTubePos(); + Tube tube = emergencyTubePos.tube; + if (tube.state.equals(TubeState.EMPTY) || tube.state.equals(TubeState.PROCESS_COMPLETE)) { + tube.userid = userid; + tube.bloodType = bloodType; + tube.sampleBarcode = sampleBarcode; + tube.projIndex.clear(); + tube.isEmergency = true; for (String index : projIndexList.split(",")) { - state.projIndex.add(Integer.parseInt(index)); + tube.projIndex.add(Integer.parseInt(index)); } - state.state = EmergencySampleState.PENDING; + tube.state = TubeState.TO_BE_PROCESSED; + sampleRecordMgrService.addEmergencySampleRecord(tube); + appSampleProcessContextMgrService.createNewTubeContext(tube); } else { throw new AppException(A8kEcode.EmergencySampleIsProcessing.index); } } @ExtApiFn(name = "获取急诊样本位状态", group = "急诊样本位状态") - public EmergencyPosRunState getEmergencyPosRunState() { - return gstate.getEmergencyPosRunState(); + public EmergencyTubePos getEmergencyPosRunState() { + return gstate.getEmergencyTubePos(); } diff --git a/src/main/java/a8k/service/appdevicectrl/action/DO_EJECT_TUBEHOLDER.java b/src/main/java/a8k/service/appdevicectrl/action/DO_EJECT_TUBEHOLDER.java deleted file mode 100644 index 04ea810..0000000 --- a/src/main/java/a8k/service/appdevicectrl/action/DO_EJECT_TUBEHOLDER.java +++ /dev/null @@ -1,57 +0,0 @@ -package a8k.service.appdevicectrl.action; - -import a8k.service.appdevicectrl.action.base.A8kActionStepType; -import a8k.service.appdevicectrl.action.base.A8kStepAction; -import a8k.service.appstate.AppA8kGStateService; -import a8k.service.appstate.MainFlowCtrlState; -import a8k.service.appstate.resource.A8kPublicResourceType; -import a8k.service.appstate.type.state.A8kWorkState; -import a8k.service.appstate.type.state.TubeHolderState; -import a8k.service.devicedriver.ctrl.SampleScanTransportCtrl; -import a8k.type.exception.AppException; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.Resource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -import java.util.List; - -@Component -public class DO_EJECT_TUBEHOLDER extends A8kStepAction { - static Logger logger = LoggerFactory.getLogger(DO_EJECT_TUBEHOLDER.class); - - DO_EJECT_TUBEHOLDER() { - super(A8kActionStepType.DO_EJECT_TUBEHOLDER); - } - - @Resource - AppA8kGStateService gstate; - @Resource - SampleScanTransportCtrl stc; - - MainFlowCtrlState mfcs; - - - @PostConstruct - void init() { - mfcs = gstate.mainFlowCtrlState; - } - - @Override public void doaction() throws AppException { - stc.ejectTubeHolder(); - stc.moveTubeRackMoveToEnterPos(); - gstate.getTubeHolder().state = TubeHolderState.IDLE; - } - - @Override public Boolean checkCondition() { - //处于工作状态,试管架已经处于空闲状态,入料光电被触发 - Boolean cond1 = mfcs.workState.equals(A8kWorkState.WORKING); - Boolean cond2 = gstate.getTubeHolder().state.equals(TubeHolderState.PROCESS_FINISHED); - return cond1 & cond2; - } - - @Override public List getDeplyResourceList() { - return List.of(A8kPublicResourceType.SampleTransferXMotor); - } -} diff --git a/src/main/java/a8k/service/appdevicectrl/action/base/A8kStepAction.java b/src/main/java/a8k/service/appdevicectrl/action/base/A8kStepAction.java index c69641e..5c8156e 100644 --- a/src/main/java/a8k/service/appdevicectrl/action/base/A8kStepAction.java +++ b/src/main/java/a8k/service/appdevicectrl/action/base/A8kStepAction.java @@ -27,7 +27,13 @@ public class A8kStepAction { } public void doaction() throws AppException { + } + + public void doactions() throws AppException { + } + public Boolean isMutiLineAction() { + return false; } public Boolean isAllowsParallelRunning() { diff --git a/src/main/java/a8k/service/appdevicectrl/action/mainflow/DO_EJECT_TUBEHOLDER.java b/src/main/java/a8k/service/appdevicectrl/action/mainflow/DO_EJECT_TUBEHOLDER.java new file mode 100644 index 0000000..23a14e8 --- /dev/null +++ b/src/main/java/a8k/service/appdevicectrl/action/mainflow/DO_EJECT_TUBEHOLDER.java @@ -0,0 +1,58 @@ +package a8k.service.appdevicectrl.action.mainflow; + +import a8k.service.appdevicectrl.action.base.A8kActionStepType; +import a8k.service.appdevicectrl.action.base.A8kStepAction; +import a8k.service.appstate.AppA8kGStateService; +import a8k.service.appstate.MainFlowCtrlState; +import a8k.service.appstate.resource.A8kPublicResourceType; +import a8k.service.appstate.type.state.A8kWorkState; +import a8k.service.appstate.type.state.TubeHolderState; +import a8k.service.devicedriver.ctrl.SampleScanTransportCtrl; +import a8k.type.exception.AppException; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class DO_EJECT_TUBEHOLDER extends A8kStepAction { + static Logger logger = LoggerFactory.getLogger(DO_EJECT_TUBEHOLDER.class); + + DO_EJECT_TUBEHOLDER() { + super(A8kActionStepType.DO_EJECT_TUBEHOLDER); + } + + @Resource + AppA8kGStateService gstate; + @Resource + SampleScanTransportCtrl stc; + + MainFlowCtrlState mfcs; + + + @PostConstruct + void init() { + mfcs = gstate.mainFlowCtrlState; + } + + @Override public void doaction() throws AppException { + stc.ejectTubeHolder(); + stc.moveTubeRackMoveToEnterPos(); + gstate.getTubeHolder().state = TubeHolderState.IDLE; + } + + @Override public Boolean checkCondition() { + //处于工作状态,试管架已经处于空闲状态,入料光电被触发 + Boolean cond1 = mfcs.workState.equals(A8kWorkState.WORKING); + Boolean cond2 = gstate.getTubeHolder().state.equals(TubeHolderState.PROCESSING); + Boolean cond3 = !gstate.getTubeHolder().isHasTubeToBeProcessed(); + return cond1 & cond2 & cond3; + } + + @Override public List getDeplyResourceList() { + return List.of(A8kPublicResourceType.SampleTransferXMotor); + } +} diff --git a/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ1_ENTER_TUBEHOLDER_AND_SCAN.java b/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ1_ENTER_TUBEHOLDER_AND_SCAN.java index 2b3f409..4f21566 100644 --- a/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ1_ENTER_TUBEHOLDER_AND_SCAN.java +++ b/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ1_ENTER_TUBEHOLDER_AND_SCAN.java @@ -5,15 +5,17 @@ import a8k.baseservice.appeventbus.appevent.AppWarningNotifyEvent; import a8k.hardware.A8kCanBusService; import a8k.hardware.type.a8kcanprotocol.A8kEcode; import a8k.hardware.type.a8kcanprotocol.IOId; -import a8k.service.appdata.AppSampleMgrService; +import a8k.service.appdata.AppSampleRecordMgrService; import a8k.service.appdevicectrl.AppTubeSettingMgrService; import a8k.service.appdevicectrl.action.base.A8kActionStepType; import a8k.service.appdevicectrl.action.base.A8kStepAction; import a8k.service.appstate.AppA8kGStateService; +import a8k.service.appstate.AppSampleProcessContextMgrService; import a8k.service.appstate.MainFlowCtrlState; import a8k.service.appstate.resource.A8kPublicResourceType; import a8k.service.appstate.type.TubeHolder; import a8k.service.appstate.type.state.TubeHolderState; +import a8k.service.appstate.type.state.TubeState; import a8k.service.devicedriver.ctrl.SampleScanTransportCtrl; import a8k.type.exception.AppException; import a8k.type.tube_setting.TubeHolderSetting; @@ -29,7 +31,11 @@ import java.util.List; /** * + * TubeHolderState + * IDLE --> PROCESSING * + * TUBES STATE + * EMPTY --> TO_BE_PROCESSED */ @Component public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction { @@ -56,17 +62,19 @@ public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction { @Resource - AppA8kGStateService gstate; + AppA8kGStateService gstate; @Resource - SampleScanTransportCtrl stc; + SampleScanTransportCtrl stc; @Resource - AppEventBusService ebus; + AppEventBusService ebus; @Resource - A8kCanBusService canBus; + A8kCanBusService canBus; @Resource - AppTubeSettingMgrService appTubeSettingMgrService; + AppTubeSettingMgrService appTubeSettingMgrService; @Resource - AppSampleMgrService appSampleMgrService; //样本管理服务 + AppSampleRecordMgrService appSampleRecordMgrService; //样本管理服务 + @Resource + AppSampleProcessContextMgrService appSampleProcessContextMgrService; MainFlowCtrlState mfcs; @@ -149,12 +157,12 @@ public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction { for (int i = 0; i < state.tubes.length; i++) { if (!scanResult.tubesScanResults[i].isTubeExist) { - state.tubes[i].isTubeExist = scanResult.tubesScanResults[i].isTubeExist; + state.tubes[i].state = TubeState.EMPTY; continue; } - state.tubes[i].isTubeExist = scanResult.tubesScanResults[i].isTubeExist; - state.tubes[i].isHighTube = scanResult.tubesScanResults[i].isHighTube; + state.tubes[i].state = TubeState.TO_BE_PROCESSED; + state.tubes[i].isHighTube = scanResult.tubesScanResults[i].isHighTube; //首先赋值默认值 @@ -184,11 +192,8 @@ public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction { // state.tubeStates[i].userid = setting.tubeSettings[i].userid; // state.tubeStates[i].projIndex = setting.tubeSettings[i].projIndex; } - - //设置试管架状态 - state.state = TubeHolderState.PROCESSING; - state.processingTubeIndex = -1; + state.state = TubeHolderState.PROCESSING; //删除之前的试管架配置 appTubeSettingMgrService.removeTubeHolderSetting(setting); return state; @@ -215,7 +220,9 @@ public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction { } logger.info("将样本信息写入数据库"); - appSampleMgrService.addSampleRecord(state.tubes); + appSampleRecordMgrService.addSampleRecord(state.tubes); + appSampleProcessContextMgrService.createNewTubeContexts(state.tubes); + logger.info("更新试管架状态"); gstate.setTubeHolder(state); @@ -235,7 +242,6 @@ public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction { return List.of(A8kPublicResourceType.SampleTransferXMotor); } - // // UTILS // diff --git a/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ2_SWITCH_TO_THE_NEXT_TUBE.java b/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ2_SWITCH_TO_THE_NEXT_TUBE.java index b192cf7..bd7e901 100644 --- a/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ2_SWITCH_TO_THE_NEXT_TUBE.java +++ b/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ2_SWITCH_TO_THE_NEXT_TUBE.java @@ -1,5 +1,8 @@ package a8k.service.appdevicectrl.action.mainflow; +import a8k.baseservice.appeventbus.AppEventBusService; +import a8k.hardware.type.a8kcanprotocol.A8kEcode; +import a8k.service.appdevicectrl.AppConsumablesMgrService; import a8k.service.appdevicectrl.action.base.A8kActionStepType; import a8k.service.appdevicectrl.action.base.A8kStepAction; import a8k.service.appstate.AppA8kGStateService; @@ -19,7 +22,11 @@ import org.springframework.stereotype.Component; import java.util.List; /** - * 切换下一个试管 + * + * 核对物料资源是否足够 + * + * TUBE + * TO_BE_PROCESSED --> PRE_PROCESSING */ @Component public class SEQ2_SWITCH_TO_THE_NEXT_TUBE extends A8kStepAction { @@ -35,72 +42,90 @@ public class SEQ2_SWITCH_TO_THE_NEXT_TUBE extends A8kStepAction { @Resource SampleScanTransportCtrl sstc; + @Resource + AppConsumablesMgrService consumablesMgrService; + + @Resource + AppEventBusService ebus; + + @PostConstruct void init() { } - int moveToNextTube() throws AppException { + int moveToNextTube() { TubeHolder state = gstate.getTubeHolder(); - assert state.tubes.length == 10; - - int nowTubeIndex = state.processingTubeIndex; int nextTubeIndex = -1; - for (int i = nowTubeIndex + 1; i < 10; i++) { - + for (int i = 0; i < 10; i++) { Tube tube = state.tubes[i]; - if (!tube.isTubeExist) { - continue; + if (tube.state.equals(TubeState.TO_BE_PROCESSED)) { + nextTubeIndex = i; + break; } - nextTubeIndex = i; - break; } - //没有下一个试管 - if (nextTubeIndex == -1) { - return -1; - } - sstc.moveTubeToPreProcessPos(nextTubeIndex); return nextTubeIndex; } + //检查是否有足够的耗材 + Boolean isHasEnoughConsumables(Tube tube) { + return consumablesMgrService.isHasEnoughConsumables(tube.projIndex); + } + + //检查孵育盘是否有空位 + Boolean checkReactionPlateResource(Tube tube) { + Integer needPos = tube.projIndex.size(); + Integer emptyNum = gstate.getIncubationPlate().getEmptyPosNum(); + return emptyNum >= needPos; + } + + + void checkIsReadyToRun(Tube tube) { + + } + @Override public void doaction() throws AppException { /* * 1. 将下一个试管移动到预处理位 * 2. 如果当前试管是最后一个试管,则设置试管架状态为处理完成。 + * 3. 检查反应板是否有空位 */ + //当前是否有有急诊试管需要处理 + Tube nextProcessTube = null; + Boolean isEmergencyTube = false; + + + if (gstate.getEmergencyTubePos().tube.state.equals(TubeState.TO_BE_PROCESSED)) { + logger.info("当前有急诊试管需要处理"); + nextProcessTube = gstate.getEmergencyTubePos().tube; + isEmergencyTube = true; + } else { + int nextPos = moveToNextTube(); + assert nextPos != -1; + nextProcessTube = gstate.getTubeHolder().tubes[nextPos]; + isEmergencyTube = false; + // logger.info("移动到下一个试管:{}", nextPos); + // sstc.moveTubeToPreProcessPos(nextPos); + // gstate.setCurProcessingTube(); + // gstate.getCurProcessingTube().state = TubeState.PRE_PROCESSING; + } - int nextPos = moveToNextTube(); - if (nextPos == -1) { - logger.info("当前试管架处理完成"); - gstate.getTubeHolder().state = TubeHolderState.PROCESS_FINISHED; - return; + if (!isHasEnoughConsumables(nextProcessTube)) { + throw new AppException(A8kEcode.ConsumeNotEnough.index); } - logger.info("移动到下一个试管:{}", nextPos); - sstc.moveTubeToPreProcessPos(nextPos); - gstate.getTubeHolder().processingTubeIndex = nextPos; } - @Override public Boolean checkCondition() { - /* - *1. 设备工作中 - * 1.1 试管架正在处理中 - * 1.2 当前Index=-1 - * - * 2.1 当前试管处理完成 - * - */ //当前正在工作 Boolean cond1 = gstate.isWorking(); - //试管架正在处理中, 且当前试管Index=-1 - Boolean cond2 = gstate.getTubeHolderState().equals(TubeHolderState.PROCESSING) && gstate.getTubeHolder().getProcessingTube() == null; - //当前<试管>处理完成 - Boolean cond3 = gstate.getTubeHolder().getProcessingTube().state.equals(TubeState.PROCESS_COMPLETE); - return cond1 && (cond2 || cond3); + //没有试管在处理 或者 当前试管处理完成 + Boolean cond2 = gstate.getCurProcessingTube() == null || gstate.getCurProcessingTube().state.equals(TubeState.PROCESS_COMPLETE); + //急诊有待处理的试管,或者试管架正在处理 + Boolean cond3 = gstate.getTubeHolder().isHasTubeToBeProcessed() || gstate.getEmergencyTubePos().tube.state.equals(TubeState.TO_BE_PROCESSED); + return cond1 && cond2 && cond3; } - @Override public List getDeplyResourceList() { return List.of(A8kPublicResourceType.SampleTransferXMotor); } diff --git a/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ3_CHECK_THE_QUANTITY_OF_CONSUMABLES.java b/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ3_CHECK_THE_QUANTITY_OF_CONSUMABLES.java index df22367..d4b5dd3 100644 --- a/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ3_CHECK_THE_QUANTITY_OF_CONSUMABLES.java +++ b/src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ3_CHECK_THE_QUANTITY_OF_CONSUMABLES.java @@ -1,13 +1,15 @@ package a8k.service.appdevicectrl.action.mainflow; +import a8k.hardware.type.a8kcanprotocol.A8kEcode; +import a8k.service.appdata.AppProjInfoMgrService; import a8k.service.appdevicectrl.action.base.A8kActionStepType; import a8k.service.appdevicectrl.action.base.A8kStepAction; import a8k.service.appstate.AppA8kGStateService; import a8k.service.appstate.resource.A8kPublicResourceType; import a8k.service.appstate.type.state.TubeHolderState; import a8k.service.appstate.type.state.TubeState; +import a8k.service.devicedriver.ctrl.SampleScanTransportCtrl; import a8k.type.exception.AppException; -import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,27 +31,55 @@ public class SEQ3_CHECK_THE_QUANTITY_OF_CONSUMABLES extends A8kStepAction { @Resource AppA8kGStateService gstate; - @PostConstruct + @Resource + SampleScanTransportCtrl sstc; + + @Resource + AppProjInfoMgrService projInfoMgrService; + void init() { } + + void checkProjResource(Integer projIndex) { + //检查项目ID卡是否存在 + // if(projInfoMgrService.) + //检查耗材 + + //申请耗材 + + //申请失败,抛出异常 + + //如果出错要归还耗材 + } + @Override public void doaction() throws AppException { - //检查孵育盘是否有空位 - // if(gstate.getIncubationPlate().getEmptyPos())){ - // } //检查当前试管的待做项目所需要的资源是否充足 +// List projIndex = gstate.getTubeHolder().getProcessingTube().projIndex; +// if (projIndex.isEmpty()) { +// logger.error("试管待处理项目为空");//属于代码异常 +// sstc.ejectTubeHolder(); +// throw new AppException(A8kEcode.CodeError.index, "试管待处理项目为空"); +// } +// +// for (Integer proj : projIndex) { +// checkProjResource(proj); +// } + + } @Override public Boolean checkCondition() { - // 仪器是否在工作 - Boolean cond1 = gstate.isWorking(); - // 试管架是否在处理中 - Boolean cond2 = gstate.getTubeHolder().state.equals(TubeHolderState.PROCESSING); - // 试管是否待处理 - Boolean cond3 = gstate.getTubeHolder().getProcessingTube() != null && gstate.getTubeHolder().getProcessingTube().state.equals(TubeState.TO_BE_PROCESSED); - // 孵育盘是否有空位 - Boolean cond4 = gstate.getIncubationPlate().getEmptyPos() != null; - return cond1 && cond2 && cond3 && cond4; +// // 仪器是否在工作 +// Boolean cond1 = gstate.isWorking(); +// // 试管架是否在处理中 +// Boolean cond2 = gstate.getTubeHolder().state.equals(TubeHolderState.PROCESSING); +// // 试管是否待处理 +// Boolean cond3 = gstate.getTubeHolder().getProcessingTube() != null && gstate.getTubeHolder().getProcessingTube().state.equals(TubeState.TO_BE_PROCESSED); +// // 孵育盘是否有空位 +// Boolean cond4 = gstate.getIncubationPlate().getEmptyPos() != null; +// return cond1 && cond2 && cond3 && cond4; + return false; } @Override public List getDeplyResourceList() { @@ -57,6 +87,6 @@ public class SEQ3_CHECK_THE_QUANTITY_OF_CONSUMABLES extends A8kStepAction { } @Override public Boolean isAllowsParallelRunning() { - return false; + return false;//串行任务,无需担心状态冲突 } } diff --git a/src/main/java/a8k/service/appstate/AppA8kGStateService.java b/src/main/java/a8k/service/appstate/AppA8kGStateService.java index a2ee8de..1729c2c 100644 --- a/src/main/java/a8k/service/appstate/AppA8kGStateService.java +++ b/src/main/java/a8k/service/appstate/AppA8kGStateService.java @@ -1,10 +1,7 @@ package a8k.service.appstate; import a8k.service.appdevicectrl.type.app_consumables_mgr_service.ConsumableState; -import a8k.service.appstate.type.EmergencyPosRunState; -import a8k.service.appstate.type.IncubationPlate; -import a8k.service.appstate.type.OptScanModule; -import a8k.service.appstate.type.TubeHolder; +import a8k.service.appstate.type.*; import a8k.service.appstate.type.state.A8kWorkState; import a8k.service.appstate.type.state.TubeHolderState; import a8k.type.tube_setting.TubeHolderSetting; @@ -29,23 +26,24 @@ public class AppA8kGStateService { A8kWorkState workState = A8kWorkState.IDLE; // //当前正在被处理的试管架状态 - TubeHolder tubeHolder = new TubeHolder(); + TubeHolder tubeHolder = new TubeHolder(); //急诊为状态 - EmergencyPosRunState emergencyPosRunState = new EmergencyPosRunState(); + EmergencyTubePos emergencyTubePos = new EmergencyTubePos(); //孵育盘状态 - IncubationPlate incubationPlate = new IncubationPlate(); + IncubationPlate incubationPlate = new IncubationPlate(); //耗材状态 - ConsumableState consumableState = new ConsumableState(); + ConsumableState consumableState = new ConsumableState(); //光学模组状态 - OptScanModule optScanModule = new OptScanModule(); + OptScanModule optScanModule = new OptScanModule(); // // 耗材状态,试管配置,急诊位样本配置,均是前端提交的设置信息 // - - //试管配置 List tubeHolderSettings = new ArrayList<>(); + //当前正在处理的试管 + Tube curProcessingTube = null; + //主流程控制状态 public MainFlowCtrlState mainFlowCtrlState = new MainFlowCtrlState(); @@ -77,4 +75,12 @@ public class AppA8kGStateService { return tubeHolder.state; } + synchronized public Tube getCurProcessingTube() { + return curProcessingTube; + } + + synchronized public void setCurProcessingTube(Tube tube) { + curProcessingTube = tube; + } + } diff --git a/src/main/java/a8k/service/appstate/AppSampleProcessContextMgrService.java b/src/main/java/a8k/service/appstate/AppSampleProcessContextMgrService.java new file mode 100644 index 0000000..664a0cc --- /dev/null +++ b/src/main/java/a8k/service/appstate/AppSampleProcessContextMgrService.java @@ -0,0 +1,46 @@ +package a8k.service.appstate; + +import a8k.service.appstate.type.Tube; +import a8k.service.appstate.type.TubeProcessContext; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class AppSampleProcessContextMgrService { + + List contexts = new ArrayList<>(); + + synchronized public void createNewTubeContext(Tube tube) { + assert tube != null; + assert !tube.sampleid.isEmpty(); + + TubeProcessContext context = new TubeProcessContext(); + context.sampleid = tube.sampleid; + context.isHighTube = tube.isHighTube; + context.isEmergency = tube.isEmergency; + context.bloodType = tube.bloodType; + context.sampleBarcode = tube.sampleBarcode; + context.userid = tube.userid; + context.projIndex = tube.projIndex; + contexts.add(context); + } + + synchronized public void createNewTubeContexts(Tube[] tube) { + for (Tube t : tube) { + createNewTubeContext(t); + } + } + + synchronized public TubeProcessContext getTubeContext(String sampleid) { + for (TubeProcessContext context : contexts) { + if (context.sampleid.equals(sampleid)) { + return context; + } + } + return null; + } + + +} diff --git a/src/main/java/a8k/service/appstate/type/EmergencyPosRunState.java b/src/main/java/a8k/service/appstate/type/EmergencyPosRunState.java deleted file mode 100644 index 00df162..0000000 --- a/src/main/java/a8k/service/appstate/type/EmergencyPosRunState.java +++ /dev/null @@ -1,19 +0,0 @@ -package a8k.service.appstate.type; - -import a8k.service.appstate.type.state.EmergencySampleState; -import a8k.type.type.BloodType; - -import java.util.ArrayList; -import java.util.List; - -/** - * 急诊位位置状态 - */ -public class EmergencyPosRunState { - public String userid = ""; //用户输入的样本ID,不做逻辑,只做展示 - public String sampleBarcode = ""; //用于请求用户信息的条码ID - public List projIndex = new ArrayList<>(); //项目代码 - public BloodType bloodType = BloodType.WHOLE_BLOOD; //血型 - - public EmergencySampleState state = EmergencySampleState.IDLE; //急诊位状态 -} diff --git a/src/main/java/a8k/service/appstate/type/EmergencyTubePos.java b/src/main/java/a8k/service/appstate/type/EmergencyTubePos.java new file mode 100644 index 0000000..ddac999 --- /dev/null +++ b/src/main/java/a8k/service/appstate/type/EmergencyTubePos.java @@ -0,0 +1,8 @@ +package a8k.service.appstate.type; + +/** + * 急诊位位置状态 + */ +public class EmergencyTubePos { + public Tube tube = new Tube(); +} diff --git a/src/main/java/a8k/service/appstate/type/IncubationPlate.java b/src/main/java/a8k/service/appstate/type/IncubationPlate.java index b03cc1b..9b21170 100644 --- a/src/main/java/a8k/service/appstate/type/IncubationPlate.java +++ b/src/main/java/a8k/service/appstate/type/IncubationPlate.java @@ -22,5 +22,15 @@ public class IncubationPlate { return null; } + public Integer getEmptyPosNum() { + Integer num = 0; + for (IncubationSubTank subtank : subtanks) { + if (subtank.state.equals(IncubationSubTankState.EMPTY)) { + num++; + } + } + return num; + } + } diff --git a/src/main/java/a8k/service/appstate/type/Tube.java b/src/main/java/a8k/service/appstate/type/Tube.java index 7d5bd8f..5ac80fa 100644 --- a/src/main/java/a8k/service/appstate/type/Tube.java +++ b/src/main/java/a8k/service/appstate/type/Tube.java @@ -10,7 +10,7 @@ public class Tube { public String sampleid; //样本ID-系统生成-唯一标识一个样本 public Boolean isHighTube = false; - public Boolean isTubeExist = false; + public Boolean isEmergency = false; public BloodType bloodType = BloodType.WHOLE_BLOOD; //血液类型 public String sampleBarcode = ""; //用于请求用户信息的条码ID @@ -18,5 +18,9 @@ public class Tube { public List projIndex = new ArrayList<>(); //项目代码 // - public TubeState state = TubeState.TO_BE_PROCESSED; //样本被处理的状态 + public TubeState state = TubeState.EMPTY; //样本被处理的状态 + + + + } diff --git a/src/main/java/a8k/service/appstate/type/TubeHolder.java b/src/main/java/a8k/service/appstate/type/TubeHolder.java index 9e856cb..7af9d19 100644 --- a/src/main/java/a8k/service/appstate/type/TubeHolder.java +++ b/src/main/java/a8k/service/appstate/type/TubeHolder.java @@ -1,14 +1,13 @@ package a8k.service.appstate.type; import a8k.service.appstate.type.state.TubeHolderState; +import a8k.service.appstate.type.state.TubeState; import a8k.type.type.A8kTubeHolderType; public class TubeHolder { public A8kTubeHolderType tubeHolderType = A8kTubeHolderType.BloodTube; //试管架类型 public Tube[] tubes = new Tube[10]; - - public TubeHolderState state = TubeHolderState.IDLE; //处理状态 - public Integer processingTubeIndex = -1; //当前正在被处理的试管索引 + public TubeHolderState state = TubeHolderState.IDLE; //处理状态 public TubeHolder() { for (int i = 0; i < tubes.length; i++) { @@ -16,11 +15,13 @@ public class TubeHolder { } } - public Tube getProcessingTube() { - if (processingTubeIndex == -1) { - return null; + public Boolean isHasTubeToBeProcessed() { + for (Tube tube : tubes) { + if (tube.state.equals(TubeState.TO_BE_PROCESSED)) { + return true; + } } - return tubes[processingTubeIndex]; + return false; } } diff --git a/src/main/java/a8k/service/appstate/type/TubeProcessContext.java b/src/main/java/a8k/service/appstate/type/TubeProcessContext.java new file mode 100644 index 0000000..0d64bd9 --- /dev/null +++ b/src/main/java/a8k/service/appstate/type/TubeProcessContext.java @@ -0,0 +1,21 @@ +package a8k.service.appstate.type; + +import a8k.type.type.BloodType; + +import java.util.ArrayList; +import java.util.List; + +public class TubeProcessContext { + public String sampleid; //样本ID-系统生成-唯一标识一个样本 + + public Boolean isHighTube = false; + public Boolean isEmergency = false; + + public BloodType bloodType = BloodType.WHOLE_BLOOD; //血液类型 + public String sampleBarcode = ""; //用于请求用户信息的条码ID + public String userid = ""; //用户输入的样本ID,不做逻辑,只做展示 + public List projIndex = new ArrayList<>(); //项目代码 + + + +} diff --git a/src/main/java/a8k/service/appstate/type/state/EmergencySampleState.java b/src/main/java/a8k/service/appstate/type/state/EmergencySampleState.java deleted file mode 100644 index 6e58342..0000000 --- a/src/main/java/a8k/service/appstate/type/state/EmergencySampleState.java +++ /dev/null @@ -1,8 +0,0 @@ -package a8k.service.appstate.type.state; - -public enum EmergencySampleState { - IDLE,// - PENDING,// - PROCESSING,// - FINISHED,// -} diff --git a/src/main/java/a8k/service/appstate/type/state/TubeHolderState.java b/src/main/java/a8k/service/appstate/type/state/TubeHolderState.java index ae70c69..74aeba8 100644 --- a/src/main/java/a8k/service/appstate/type/state/TubeHolderState.java +++ b/src/main/java/a8k/service/appstate/type/state/TubeHolderState.java @@ -3,5 +3,4 @@ package a8k.service.appstate.type.state; public enum TubeHolderState { IDLE, //没有试管架 PROCESSING, //正在处理试管架 - PROCESS_FINISHED, //试管架处理完成,但试管架并没有被取走 } diff --git a/src/main/java/a8k/service/appstate/type/state/TubeState.java b/src/main/java/a8k/service/appstate/type/state/TubeState.java index 3d07dd7..b637de1 100644 --- a/src/main/java/a8k/service/appstate/type/state/TubeState.java +++ b/src/main/java/a8k/service/appstate/type/state/TubeState.java @@ -2,9 +2,13 @@ package a8k.service.appstate.type.state; public enum TubeState { // + EMPTY,//空 TO_BE_PROCESSED,//待处理 PRE_PROCESSING, //预处理 - PROCESSING,//预处理 + PRE_PROCESSED, //预处理结束 + PROCESSING,//处理 + PROCESSED,//处理完成 POST_PROCESSING, //后处理 + POST_PROCESSED, //后处理完成 PROCESS_COMPLETE,//处理完成 } diff --git a/src/main/java/a8k/service/devicedriver/ctrl/ConsumablesScanCtrl.java b/src/main/java/a8k/service/devicedriver/ctrl/ConsumablesScanCtrl.java index 5b1ddb1..9b8618f 100644 --- a/src/main/java/a8k/service/devicedriver/ctrl/ConsumablesScanCtrl.java +++ b/src/main/java/a8k/service/devicedriver/ctrl/ConsumablesScanCtrl.java @@ -16,10 +16,26 @@ import org.springframework.stereotype.Component; @ExtApiTab(cfg = ExtApiTabConfig.HbotControlService) public class ConsumablesScanCtrl { - public static class ConsumablesScanRawResult { - public String[] PBScanResult = new String[6]; - public String[] littBSScanResult = new String[6]; - public String[] larBSScanResult = new String[6]; + public static class ScanRawResult { + public OneChResult[] ch = new OneChResult[6]; + + public ScanRawResult() { + for (int i = 0; i < 6; i++) { + ch[i] = new OneChResult(i); + } + } + } + + public static class OneChResult { + + public Integer chNum; + public String PBScanResult = ""; + public String littBSScanResult = ""; + public String larBSScanResult = ""; + + OneChResult(int chNum) { + this.chNum = chNum; + } } @@ -66,22 +82,22 @@ public class ConsumablesScanCtrl { @ExtApiFn(name = "扫描耗材") - public ConsumablesScanRawResult doScanConsumablesAction() throws AppException { + public ScanRawResult doScanConsumablesAction() throws AppException { if (!stateMgrService.isDeviceInited()) { throw new AppException(A8kEcode.DeviceNotInited.index); } - ConsumablesScanRawResult result = new ConsumablesScanRawResult(); + ScanRawResult result = new ScanRawResult(); for (int i = 0; i < 6; i++) { int finalI = i; - ar.dosome("扫描耗材-板夹0", () -> result.PBScanResult[finalI] = scanPB(finalI)); + ar.dosome("扫描耗材-板夹0", () -> result.ch[finalI].PBScanResult = scanPB(finalI)); } for (int i = 0; i < 6; i++) { int finalI = i; - ar.dosome("扫描耗材-小瓶缓冲液", () -> result.littBSScanResult[finalI] = scanLittBS(finalI)); + ar.dosome("扫描耗材-小瓶缓冲液", () -> result.ch[finalI].littBSScanResult = scanLittBS(finalI)); } for (int i = 0; i < 6; i++) { int finalI = i; - ar.dosome("扫描耗材-大瓶缓冲液", () -> result.larBSScanResult[finalI] = scanLarBS(finalI)); + ar.dosome("扫描耗材-大瓶缓冲液", () -> result.ch[finalI].larBSScanResult = scanLarBS(finalI)); } hbotMoveTo(new Pos2d(0, 0)); @@ -89,17 +105,25 @@ public class ConsumablesScanCtrl { * 清空 result 中的所有\r */ for (int i = 0; i < 6; i++) { - if (result.PBScanResult[i] != null) { - result.PBScanResult[i] = result.PBScanResult[i].replaceAll("\r", ""); + if (result.ch[i].PBScanResult != null) { + result.ch[i].PBScanResult = result.ch[i].PBScanResult.replaceAll("\r", ""); } - if (result.littBSScanResult[i] != null) { - result.littBSScanResult[i] = result.littBSScanResult[i].replaceAll("\r", ""); + if (result.ch[i].littBSScanResult != null) { + result.ch[i].littBSScanResult = result.ch[i].littBSScanResult.replaceAll("\r", ""); } - if (result.larBSScanResult[i] != null) { - result.larBSScanResult[i] = result.larBSScanResult[i].replaceAll("\r", ""); + if (result.ch[i].larBSScanResult != null) { + result.ch[i].larBSScanResult = result.ch[i].larBSScanResult.replaceAll("\r", ""); } } return result; } + @ExtApiFn(name = "扫描单个耗材") + public OneChResult doScanOneCh(Integer ch) throws AppException { + OneChResult result = new OneChResult(ch); + ar.dosome("扫描耗材-板夹0", () -> result.PBScanResult = scanPB(ch)); + ar.dosome("扫描耗材-小瓶缓冲液", () -> result.littBSScanResult = scanLittBS(ch)); + ar.dosome("扫描耗材-大瓶缓冲液", () -> result.larBSScanResult = scanLarBS(ch)); + return result; + } }