Browse Source

update

tags/v0
zhaohe 10 months ago
parent
commit
4a7a8029d4
  1. 27
      README.md
  2. 1
      src/main/java/a8k/controler/extapi/pagecontrol/ExtApiTabConfig.java
  3. 1
      src/main/java/a8k/dbservice/type/SampleRecord.java
  4. 78
      src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java
  5. 2
      src/main/java/a8k/service/appdata/AppProjInfoMgrService.java
  6. 27
      src/main/java/a8k/service/appdata/AppSampleRecordMgrService.java
  7. 206
      src/main/java/a8k/service/appdevicectrl/AppConsumablesMgrService.java
  8. 50
      src/main/java/a8k/service/appdevicectrl/AppEmergencySamplePosStateMgrService.java
  9. 6
      src/main/java/a8k/service/appdevicectrl/action/base/A8kStepAction.java
  10. 7
      src/main/java/a8k/service/appdevicectrl/action/mainflow/DO_EJECT_TUBEHOLDER.java
  11. 38
      src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ1_ENTER_TUBEHOLDER_AND_SCAN.java
  12. 103
      src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ2_SWITCH_TO_THE_NEXT_TUBE.java
  13. 60
      src/main/java/a8k/service/appdevicectrl/action/mainflow/SEQ3_CHECK_THE_QUANTITY_OF_CONSUMABLES.java
  14. 28
      src/main/java/a8k/service/appstate/AppA8kGStateService.java
  15. 46
      src/main/java/a8k/service/appstate/AppSampleProcessContextMgrService.java
  16. 8
      src/main/java/a8k/service/appstate/type/EmergencyTubePos.java
  17. 10
      src/main/java/a8k/service/appstate/type/IncubationPlate.java
  18. 8
      src/main/java/a8k/service/appstate/type/Tube.java
  19. 15
      src/main/java/a8k/service/appstate/type/TubeHolder.java
  20. 18
      src/main/java/a8k/service/appstate/type/TubeProcessContext.java
  21. 8
      src/main/java/a8k/service/appstate/type/state/EmergencySampleState.java
  22. 1
      src/main/java/a8k/service/appstate/type/state/TubeHolderState.java
  23. 6
      src/main/java/a8k/service/appstate/type/state/TubeState.java
  24. 54
      src/main/java/a8k/service/devicedriver/ctrl/ConsumablesScanCtrl.java

27
README.md

@ -149,10 +149,14 @@ TODO:
``` ```
动作: 动作:
入料并扫描 入料并扫描
将下一个试管移动到预处理位
准备下一个样本
条件: 当前正在处理的样本处理完成 &&
急诊位Pending | 还有剩余试管未处理
核对资源是否可以被处理
样本处理
BEFORE_PROCESS 预处理A(脱帽,摇匀) BEFORE_PROCESS 预处理A(脱帽,摇匀)
BEFORE_PROCESS 预处理B(hbot取tip头,移动到待机位) BEFORE_PROCESS 预处理B(hbot取tip头,移动到待机位)
BEFORE_PROCESS 预处理C(推出反应板夹) BEFORE_PROCESS 预处理C(推出反应板夹)
@ -160,11 +164,14 @@ TODO:
PROCESS 处理(取样,处理,滴定) PROCESS 处理(取样,处理,滴定)
AFTER_PROCESS 后处理 AFTER_PROCESS 后处理
出料
将反应板推出到光学扫描位 将反应板推出到光学扫描位
光学扫描 光学扫描
代码规范 代码规范
1. 什么样的检查写在动作中? 1. 什么样的检查写在动作中?
需要进行报错处理的检查写在步骤中 需要进行报错处理的检查写在步骤中
@ -185,4 +192,18 @@ TODO:
5. 支持吸空检测。 5. 支持吸空检测。
6. 支持反应板夹类型检测。 6. 支持反应板夹类型检测。
```
```
TODO:
1. 如果当前板夹仓对应位置的耗材批次码没有发生变化,则耗材量不重新初始化。
2. tip头只有在第一次扫描时,才会初始化其数量是满的。
``` ```

1
src/main/java/a8k/controler/extapi/pagecontrol/ExtApiTabConfig.java

@ -10,7 +10,6 @@ public enum ExtApiTabConfig {
AppUserMgrService("应用数据.用户管理", true), //Ok AppUserMgrService("应用数据.用户管理", true), //Ok
AppSettingsMgr("应用数据.设备配置管理", true), //OK AppSettingsMgr("应用数据.设备配置管理", true), //OK
AppProjectItemMgrService("应用数据.ID卡状态管理", true), //OK
AppProjInfoMgrService("应用数据.项目信息管理", true), //OK AppProjInfoMgrService("应用数据.项目信息管理", true), //OK
AppReactionResultMgrService("应用数据.反应结果管理", true), //OK AppReactionResultMgrService("应用数据.反应结果管理", true), //OK
AppSampleMgrService("应用数据.样本管理", true), //OK AppSampleMgrService("应用数据.样本管理", true), //OK

1
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 String sampleid; // generated by system , year%100+month+day+时分 241230_1203_01
public Date date; public Date date;
public BloodType bloodType = BloodType.WHOLE_BLOOD; //血液类型 public BloodType bloodType = BloodType.WHOLE_BLOOD; //血液类型
public Boolean isEmergency = false; //是否急诊
public String sampleBarcode = ""; //用于请求用户信息的条码ID public String sampleBarcode = ""; //用于请求用户信息的条码ID
public String userid = ""; //用户输入的样本ID不做逻辑只做展示 public String userid = ""; //用户输入的样本ID不做逻辑只做展示
public List<Integer> projIndex = new ArrayList<>(); //项目代码,逗号分隔 public List<Integer> projIndex = new ArrayList<>(); //项目代码,逗号分隔

78
src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java

@ -57,6 +57,7 @@ public enum A8kEcode {
TubeHolderSettingNotFound(139),//试管架设置未找到 TubeHolderSettingNotFound(139),//试管架设置未找到
TubeHolderTypeIsNotSupport(140),//试管架类型不支持 TubeHolderTypeIsNotSupport(140),//试管架类型不支持
EmergencySampleIsProcessing(141),//急诊样本正在处理中 EmergencySampleIsProcessing(141),//急诊样本正在处理中
ConsumeNotEnough(142),//耗材不足
/** /**
* 特殊服务错误码 * 特殊服务错误码
@ -66,164 +67,87 @@ public enum A8kEcode {
* 其他 * 其他
*/ */
ActionReactorService_breakByUsr(900), ActionReactorService_breakByUsr(900),
OS_threadInterrupt(901),//Sleep被中断 OS_threadInterrupt(901),//Sleep被中断
TestScrip_deviceIsBusy(902), TestScrip_deviceIsBusy(902),
CheckPoint_checkFail(903), //检查点检查失败 CheckPoint_checkFail(903), //检查点检查失败
// //
// LowBoard // LowBoard
// //
HardwareErrorStart(1000), HardwareErrorStart(1000),
BoardCommonError(1001), BoardCommonError(1001),
ParamOutOfRange(1102), ParamOutOfRange(1102),
CmdNotSupport(1103), CmdNotSupport(1103),
DeviceIsBusy(1104), DeviceIsBusy(1104),
DeviceIsOffline(1105), DeviceIsOffline(1105),
Overtime(1106), Overtime(1106),
Noack(1107), Noack(1107),
Errorack(1108), Errorack(1108),
DeviceOffline(1109), DeviceOffline(1109),
SubdeviceOvertime(1111), SubdeviceOvertime(1111),
BufferNotEnough(1112), BufferNotEnough(1112),
CmdParamNumError(1114), CmdParamNumError(1114),
CheckcodeIsError(1115), CheckcodeIsError(1115),
IllegalOperation(1116), IllegalOperation(1116),
ActionOvertime(1117), ActionOvertime(1117),
ModuleOpeationBreakByUser(1202), ModuleOpeationBreakByUser(1202),
ModuleNotFindReg(1207), ModuleNotFindReg(1207),
XymotorXFindZeroEdgeFail(1306), XymotorXFindZeroEdgeFail(1306),
XymotorYFindZeroEdgeFail(1307), XymotorYFindZeroEdgeFail(1307),
XymotorNotEnable(1308), XymotorNotEnable(1308),
XymotorTargetPosOutofRange(1309), XymotorTargetPosOutofRange(1309),
XymotorNotMoveToZero(1310), XymotorNotMoveToZero(1310),
PipetteErrorNoError(1400), PipetteErrorNoError(1400),
PipetteErrorInitFail(1401), PipetteErrorInitFail(1401),
PipetteErrorInvalidCmd(1402), PipetteErrorInvalidCmd(1402),
PipetteErrorInvalidArg(1403), PipetteErrorInvalidArg(1403),
PipetteErrorPressureSensorError(1404), PipetteErrorPressureSensorError(1404),
PipetteErrorOverPressure(1405), PipetteErrorOverPressure(1405),
PipetteErrorLldError(1406), PipetteErrorLldError(1406),
PipetteErrorDeviceNotInit(1407), PipetteErrorDeviceNotInit(1407),
PipetteErrorTipPopError(1408), PipetteErrorTipPopError(1408),
PipetteErrorPumpOverload(1409), PipetteErrorPumpOverload(1409),
PipetteErrorTipDrop(1410), PipetteErrorTipDrop(1410),
PipetteErrorCanBusError(1411), PipetteErrorCanBusError(1411),
PipetteErrorInvalidChecksum(1412), PipetteErrorInvalidChecksum(1412),
PipetteErrorEepromError(1413), PipetteErrorEepromError(1413),
PipetteErrorCmdBufferEmpty(1414), PipetteErrorCmdBufferEmpty(1414),
PipetteErrorCmdBufferOverflow(1415), PipetteErrorCmdBufferOverflow(1415),
PipetteErrorTipBlock(1416), PipetteErrorTipBlock(1416),
PipetteErrorAirSuction(1417), PipetteErrorAirSuction(1417),
PipetteErrorBubble(1418), PipetteErrorBubble(1418),
PipetteErrorVolumeError(1419), PipetteErrorVolumeError(1419),
PipetteErrorTipAlreadyLoad(1420), PipetteErrorTipAlreadyLoad(1420),
PipetteErrorTipLoadFail(1421), PipetteErrorTipLoadFail(1421),
PipetteErrorUninited(1501), PipetteErrorUninited(1501),
PipetteErrorNotLldPrepare(1502), PipetteErrorNotLldPrepare(1502),
PipetteErrorTipisloadWhenLldPrepare(1500), PipetteErrorTipisloadWhenLldPrepare(1500),
PipetteErrorPumpLoadValIsNotEmpty(1503), PipetteErrorPumpLoadValIsNotEmpty(1503),
StepMotorNotFoundZeroPoint(1600), StepMotorNotFoundZeroPoint(1600),
StepMotorNotGoZero(1601), StepMotorNotGoZero(1601),
StepMotorOverTemperature(1602), StepMotorOverTemperature(1602),
StepMotorOverVoltage(1603), StepMotorOverVoltage(1603),
StepMotorRunOvertime(1604), StepMotorRunOvertime(1604),
StepMotorNotEnable(1605), StepMotorNotEnable(1605),
StepMotorIoindexOutOfRange(1606), StepMotorIoindexOutOfRange(1606),
StepMotorSubicReset(1607), StepMotorSubicReset(1607),
StepMotorDrvErr(1608), StepMotorDrvErr(1608),
StepMotorUvCp(1609), StepMotorUvCp(1609),
StepMotorNotFoundPointEdge(1610), StepMotorNotFoundPointEdge(1610),
StepMotorLostStep(1611), StepMotorLostStep(1611),
StepMotorNotMoveToZero(1612), StepMotorNotMoveToZero(1612),
StepMotorOt(1613), StepMotorOt(1613),
StepMotorOtpw(1614), StepMotorOtpw(1614),
StepMotorS2ga(1615), StepMotorS2ga(1615),
StepMotorS2gb(1616), StepMotorS2gb(1616),
StepMotorOla(1617), StepMotorOla(1617),
StepMotorOlb(1618), StepMotorOlb(1618),
MiniServoNotEnable(1700), MiniServoNotEnable(1700),
MiniServoModeNotSupport(1701), MiniServoModeNotSupport(1701),
FanHardwareFault(1800), FanHardwareFault(1800),
WaterCoolingFanError(1900), WaterCoolingFanError(1900),
WaterCoolingTemperatureSensorError(1902), WaterCoolingTemperatureSensorError(1902),
WaterCoolingPumpIsError(1903), WaterCoolingPumpIsError(1903),
WaterCoolingPelterIsError(1904), WaterCoolingPelterIsError(1904),
; ;

2
src/main/java/a8k/service/appdata/AppProjInfoMgrService.java

@ -26,7 +26,7 @@ import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@Component @Component
@ExtApiTab(cfg = ExtApiTabConfig.AppProjectItemMgrService)
@ExtApiTab(cfg = ExtApiTabConfig.AppProjInfoMgrService)
public class AppProjInfoMgrService implements AppEventListener { public class AppProjInfoMgrService implements AppEventListener {
static Logger logger = org.slf4j.LoggerFactory.getLogger(AppProjInfoMgrService.class); static Logger logger = org.slf4j.LoggerFactory.getLogger(AppProjInfoMgrService.class);

27
src/main/java/a8k/service/appdata/AppSampleMgrService.java → src/main/java/a8k/service/appdata/AppSampleRecordMgrService.java

@ -6,6 +6,7 @@ import a8k.controler.extapi.utils.ExtApiTab;
import a8k.dbservice.SampleRecordDBService; import a8k.dbservice.SampleRecordDBService;
import a8k.dbservice.type.SampleRecord; import a8k.dbservice.type.SampleRecord;
import a8k.service.appstate.type.Tube; import a8k.service.appstate.type.Tube;
import a8k.service.appstate.type.state.TubeState;
import a8k.type.type.BloodType; import a8k.type.type.BloodType;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -17,7 +18,7 @@ import java.util.List;
@Component @Component
@ExtApiTab(cfg = ExtApiTabConfig.AppSampleMgrService) @ExtApiTab(cfg = ExtApiTabConfig.AppSampleMgrService)
public class AppSampleMgrService {
public class AppSampleRecordMgrService {
@Resource @Resource
SampleRecordDBService sampleRecordDBService; SampleRecordDBService sampleRecordDBService;
@ -31,7 +32,10 @@ public class AppSampleMgrService {
String generateSampleId(Date date, Integer tubePos) { String generateSampleId(Date date, Integer tubePos) {
String sampleid = ""; String sampleid = "";
SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd_HHmmss"); SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd_HHmmss");
sampleid = String.format("%s_%s", sdf.format(date), tubePos);
sampleid = String.format("%s_%s", sdf.format(date), tubePos + 1);
if (tubePos == -1) {
sampleid = String.format("%s_%s", sdf.format(date), "E");
}
return sampleid; return sampleid;
} }
@ -65,7 +69,7 @@ public class AppSampleMgrService {
if (state[i] == null) { if (state[i] == null) {
continue; continue;
} }
if (!state[i].isTubeExist) {
if (state[i].state.equals(TubeState.EMPTY)) {
continue; continue;
} }
SampleRecord record = new SampleRecord(); SampleRecord record = new SampleRecord();
@ -73,6 +77,7 @@ public class AppSampleMgrService {
record.sampleBarcode = state[i].sampleBarcode; record.sampleBarcode = state[i].sampleBarcode;
record.userid = state[i].userid; record.userid = state[i].userid;
record.date = intertime; record.date = intertime;
record.isEmergency = state[i].isEmergency;
record.sampleid = generateSampleId(intertime, i); record.sampleid = generateSampleId(intertime, i);
record.projIndex = state[i].projIndex; record.projIndex = state[i].projIndex;
state[i].sampleid = record.sampleid; state[i].sampleid = record.sampleid;
@ -80,5 +85,21 @@ public class AppSampleMgrService {
} }
} }
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);
}
} }

206
src/main/java/a8k/service/appdevicectrl/AppConsumablesMgrService.java

@ -36,10 +36,6 @@ public class AppConsumablesMgrService {
@Resource @Resource
ConsumablesScanCtrl scanCtrlService; ConsumablesScanCtrl scanCtrlService;
public ConsumablesScanCtrl.ConsumablesScanRawResult doScanConsumablesAction() throws AppException {
return scanCtrlService.doScanConsumablesAction();
}
/** /**
* 解析扫描结果返回耗材扫描结果 * 解析扫描结果返回耗材扫描结果
* *
@ -47,22 +43,22 @@ public class AppConsumablesMgrService {
* @param rawResult 原始扫描结果 * @param rawResult 原始扫描结果
* @return 耗材扫描结果 * @return 耗材扫描结果
*/ */
ConsumablesScanResult parseScanResult(Integer ch, ConsumablesScanCtrl.ConsumablesScanRawResult rawResult) throws AppException {
ConsumablesScanResult parseScanResult(Integer ch, ConsumablesScanCtrl.OneChResult rawResult) throws AppException {
ConsumablesScanResult ret = new ConsumablesScanResult(); ConsumablesScanResult ret = new ConsumablesScanResult();
ret.chNum = ch; 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; ret.state = ScanResultState.Empty;
return ret; return ret;
} }
if (rawResult.PBScanResult[ch] == null) {
if (rawResult.PBScanResult == null) {
ret.state = ScanResultState.LostReactionPlate; ret.state = ScanResultState.LostReactionPlate;
return ret; return ret;
} }
//解析板夹二维码 //解析板夹二维码
ReactionPlate2DCode rp2dcode = ReactionPlate2DCodeParser.parse(rawResult.PBScanResult[ch]);
ReactionPlate2DCode rp2dcode = ReactionPlate2DCodeParser.parse(rawResult.PBScanResult);
//检查耗材是否过期 //检查耗材是否过期
if (rp2dcode.expDate.before(new Date())) { if (rp2dcode.expDate.before(new Date())) {
@ -87,13 +83,13 @@ public class AppConsumablesMgrService {
if (reactionType.equals(A8kReactionFlowType.ReactionWithLittBS)) { if (reactionType.equals(A8kReactionFlowType.ReactionWithLittBS)) {
//校验小瓶缓冲液,小瓶缓冲液+样本 //校验小瓶缓冲液,小瓶缓冲液+样本
if (rawResult.littBSScanResult[ch] == null) {
if (rawResult.littBSScanResult == null) {
ret.state = ScanResultState.LostLittSB; ret.state = ScanResultState.LostLittSB;
return ret; return ret;
} }
} else if (reactionType.equals(A8kReactionFlowType.ReactionWithLarBsAndDetection)) { } else if (reactionType.equals(A8kReactionFlowType.ReactionWithLarBsAndDetection)) {
// 校验大瓶缓冲液,大瓶缓冲液+小瓶缓冲液+样本 // 校验大瓶缓冲液,大瓶缓冲液+小瓶缓冲液+样本
if (rawResult.larBSScanResult[ch] == null) {
if (rawResult.larBSScanResult == null) {
ret.state = ScanResultState.LostLarBS; ret.state = ScanResultState.LostLarBS;
return ret; return ret;
} }
@ -106,77 +102,84 @@ public class AppConsumablesMgrService {
return ret; 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<String, Object> 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<ConsumablesScanResult> scanResult = new java.util.ArrayList<>();
//执行扫描耗材动作
var scanRawResult = doScanConsumablesAction();
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* EXT
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
@ExtApiFn(name = "扫描耗材(阻塞接口)", order = 1)
public Map<String, Object> scanConsumables() throws AppException {
if (!gstate.isDeviceInited()) {
throw new AppException(A8kEcode.DeviceNotInited.index);
}
List<ConsumablesScanResult> scanResult = new java.util.ArrayList<>();
//执行扫描耗材动作
var scanRawResult = scanCtrlService.doScanConsumablesAction();
//解析扫描结果 //解析扫描结果
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
var result = parseScanResult(i, scanRawResult);
var result = parseScanResult(i, scanRawResult.ch[i]);
scanResult.add(result); 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++) { for (int i = 0; i < cState.reactionPlateGroup.length; i++) {
if (scanResult.get(i).state == ScanResultState.PASS) { 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("scanResult", scanResult);
ret.put("scanRawResult", scanRawResult); ret.put("scanRawResult", scanRawResult);
ret.put("consumableState", cState); ret.put("consumableState", cState);
gstate.setConsumableState(cState);
return ret; return ret;
} }
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* EXT
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
@ExtApiFn(name = "扫描耗材(阻塞接口)", order = 1)
public Map<String, Object> scanConsumables() throws AppException {
return doScanConsumables();
@ExtApiFn(name = "扫描某一个通道耗材(阻塞接口)", order = 1)
public Map<String, Object> scanOneChConsumables(Integer chNum) throws AppException {
if (!gstate.isDeviceInited()) {
throw new AppException(A8kEcode.DeviceNotInited.index);
}
List<ConsumablesScanResult> 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<String, Object> 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; 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<Integer> projIndex) {
//
//只检查反应板的数量即可
for (Integer index : projIndex) {
Integer total = getConsumableNum(index);
if (total < 1) {
return false;
}
}
return false;
}
} }

50
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.ExtApiFn;
import a8k.controler.extapi.utils.ExtApiTab; import a8k.controler.extapi.utils.ExtApiTab;
import a8k.hardware.type.a8kcanprotocol.A8kEcode; import a8k.hardware.type.a8kcanprotocol.A8kEcode;
import a8k.service.appdata.AppSampleRecordMgrService;
import a8k.service.appstate.AppA8kGStateService; 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.exception.AppException;
import a8k.type.type.BloodType; import a8k.type.type.BloodType;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -20,22 +23,11 @@ public class AppEmergencySamplePosStateMgrService {
@Resource @Resource
AppA8kGStateService gstate; 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 = "紧急样本设置") @ExtApiFn(name = "提交紧急样本设置", group = "紧急样本设置")
public void commitEmergencySampleSetting(String userid, String sampleBarcode, BloodType bloodType,// public void commitEmergencySampleSetting(String userid, String sampleBarcode, BloodType bloodType,//
@EnginnerPageActionParam(name = "逗号分割项目列表(例子1,2,3)") String projIndexList) throws AppException { @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(",")) { 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 { } else {
throw new AppException(A8kEcode.EmergencySampleIsProcessing.index); throw new AppException(A8kEcode.EmergencySampleIsProcessing.index);
} }
} }
@ExtApiFn(name = "获取急诊样本位状态", group = "急诊样本位状态") @ExtApiFn(name = "获取急诊样本位状态", group = "急诊样本位状态")
public EmergencyPosRunState getEmergencyPosRunState() {
return gstate.getEmergencyPosRunState();
public EmergencyTubePos getEmergencyPosRunState() {
return gstate.getEmergencyTubePos();
} }

6
src/main/java/a8k/service/appdevicectrl/action/base/A8kStepAction.java

@ -27,7 +27,13 @@ public class A8kStepAction {
} }
public void doaction() throws AppException { public void doaction() throws AppException {
}
public void doactions() throws AppException {
}
public Boolean isMutiLineAction() {
return false;
} }
public Boolean isAllowsParallelRunning() { public Boolean isAllowsParallelRunning() {

7
src/main/java/a8k/service/appdevicectrl/action/DO_EJECT_TUBEHOLDER.java → src/main/java/a8k/service/appdevicectrl/action/mainflow/DO_EJECT_TUBEHOLDER.java

@ -1,4 +1,4 @@
package a8k.service.appdevicectrl.action;
package a8k.service.appdevicectrl.action.mainflow;
import a8k.service.appdevicectrl.action.base.A8kActionStepType; import a8k.service.appdevicectrl.action.base.A8kActionStepType;
import a8k.service.appdevicectrl.action.base.A8kStepAction; import a8k.service.appdevicectrl.action.base.A8kStepAction;
@ -47,8 +47,9 @@ public class DO_EJECT_TUBEHOLDER extends A8kStepAction {
@Override public Boolean checkCondition() { @Override public Boolean checkCondition() {
//处于工作状态试管架已经处于空闲状态入料光电被触发 //处于工作状态试管架已经处于空闲状态入料光电被触发
Boolean cond1 = mfcs.workState.equals(A8kWorkState.WORKING); Boolean cond1 = mfcs.workState.equals(A8kWorkState.WORKING);
Boolean cond2 = gstate.getTubeHolder().state.equals(TubeHolderState.PROCESS_FINISHED);
return cond1 & cond2;
Boolean cond2 = gstate.getTubeHolder().state.equals(TubeHolderState.PROCESSING);
Boolean cond3 = !gstate.getTubeHolder().isHasTubeToBeProcessed();
return cond1 & cond2 & cond3;
} }
@Override public List<A8kPublicResourceType> getDeplyResourceList() { @Override public List<A8kPublicResourceType> getDeplyResourceList() {

38
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.A8kCanBusService;
import a8k.hardware.type.a8kcanprotocol.A8kEcode; import a8k.hardware.type.a8kcanprotocol.A8kEcode;
import a8k.hardware.type.a8kcanprotocol.IOId; 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.AppTubeSettingMgrService;
import a8k.service.appdevicectrl.action.base.A8kActionStepType; import a8k.service.appdevicectrl.action.base.A8kActionStepType;
import a8k.service.appdevicectrl.action.base.A8kStepAction; import a8k.service.appdevicectrl.action.base.A8kStepAction;
import a8k.service.appstate.AppA8kGStateService; import a8k.service.appstate.AppA8kGStateService;
import a8k.service.appstate.AppSampleProcessContextMgrService;
import a8k.service.appstate.MainFlowCtrlState; import a8k.service.appstate.MainFlowCtrlState;
import a8k.service.appstate.resource.A8kPublicResourceType; import a8k.service.appstate.resource.A8kPublicResourceType;
import a8k.service.appstate.type.TubeHolder; import a8k.service.appstate.type.TubeHolder;
import a8k.service.appstate.type.state.TubeHolderState; import a8k.service.appstate.type.state.TubeHolderState;
import a8k.service.appstate.type.state.TubeState;
import a8k.service.devicedriver.ctrl.SampleScanTransportCtrl; import a8k.service.devicedriver.ctrl.SampleScanTransportCtrl;
import a8k.type.exception.AppException; import a8k.type.exception.AppException;
import a8k.type.tube_setting.TubeHolderSetting; import a8k.type.tube_setting.TubeHolderSetting;
@ -29,7 +31,11 @@ import java.util.List;
/** /**
* *
* TubeHolderState
* IDLE --> PROCESSING
* *
* TUBES STATE
* EMPTY --> TO_BE_PROCESSED
*/ */
@Component @Component
public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction { public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction {
@ -56,17 +62,19 @@ public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction {
@Resource @Resource
AppA8kGStateService gstate;
AppA8kGStateService gstate;
@Resource @Resource
SampleScanTransportCtrl stc;
SampleScanTransportCtrl stc;
@Resource @Resource
AppEventBusService ebus;
AppEventBusService ebus;
@Resource @Resource
A8kCanBusService canBus;
A8kCanBusService canBus;
@Resource @Resource
AppTubeSettingMgrService appTubeSettingMgrService;
AppTubeSettingMgrService appTubeSettingMgrService;
@Resource @Resource
AppSampleMgrService appSampleMgrService; //样本管理服务
AppSampleRecordMgrService appSampleRecordMgrService; //样本管理服务
@Resource
AppSampleProcessContextMgrService appSampleProcessContextMgrService;
MainFlowCtrlState mfcs; MainFlowCtrlState mfcs;
@ -149,12 +157,12 @@ public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction {
for (int i = 0; i < state.tubes.length; i++) { for (int i = 0; i < state.tubes.length; i++) {
if (!scanResult.tubesScanResults[i].isTubeExist) { if (!scanResult.tubesScanResults[i].isTubeExist) {
state.tubes[i].isTubeExist = scanResult.tubesScanResults[i].isTubeExist;
state.tubes[i].state = TubeState.EMPTY;
continue; 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].userid = setting.tubeSettings[i].userid;
// state.tubeStates[i].projIndex = setting.tubeSettings[i].projIndex; // state.tubeStates[i].projIndex = setting.tubeSettings[i].projIndex;
} }
//设置试管架状态 //设置试管架状态
state.state = TubeHolderState.PROCESSING;
state.processingTubeIndex = -1;
state.state = TubeHolderState.PROCESSING;
//删除之前的试管架配置 //删除之前的试管架配置
appTubeSettingMgrService.removeTubeHolderSetting(setting); appTubeSettingMgrService.removeTubeHolderSetting(setting);
return state; return state;
@ -215,7 +220,9 @@ public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction {
} }
logger.info("将样本信息写入数据库"); logger.info("将样本信息写入数据库");
appSampleMgrService.addSampleRecord(state.tubes);
appSampleRecordMgrService.addSampleRecord(state.tubes);
appSampleProcessContextMgrService.createNewTubeContexts(state.tubes);
logger.info("更新试管架状态"); logger.info("更新试管架状态");
gstate.setTubeHolder(state); gstate.setTubeHolder(state);
@ -235,7 +242,6 @@ public class SEQ1_ENTER_TUBEHOLDER_AND_SCAN extends A8kStepAction {
return List.of(A8kPublicResourceType.SampleTransferXMotor); return List.of(A8kPublicResourceType.SampleTransferXMotor);
} }
// //
// UTILS // UTILS
// //

103
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; 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.A8kActionStepType;
import a8k.service.appdevicectrl.action.base.A8kStepAction; import a8k.service.appdevicectrl.action.base.A8kStepAction;
import a8k.service.appstate.AppA8kGStateService; import a8k.service.appstate.AppA8kGStateService;
@ -19,7 +22,11 @@ import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
/** /**
* 切换下一个试管
*
* 核对物料资源是否足够
*
* TUBE
* TO_BE_PROCESSED --> PRE_PROCESSING
*/ */
@Component @Component
public class SEQ2_SWITCH_TO_THE_NEXT_TUBE extends A8kStepAction { 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 @Resource
SampleScanTransportCtrl sstc; SampleScanTransportCtrl sstc;
@Resource
AppConsumablesMgrService consumablesMgrService;
@Resource
AppEventBusService ebus;
@PostConstruct @PostConstruct
void init() { void init() {
} }
int moveToNextTube() throws AppException {
int moveToNextTube() {
TubeHolder state = gstate.getTubeHolder(); TubeHolder state = gstate.getTubeHolder();
assert state.tubes.length == 10; assert state.tubes.length == 10;
int nowTubeIndex = state.processingTubeIndex;
int nextTubeIndex = -1; int nextTubeIndex = -1;
for (int i = nowTubeIndex + 1; i < 10; i++) {
for (int i = 0; i < 10; i++) {
Tube tube = state.tubes[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; 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 { @Override public void doaction() throws AppException {
/* /*
* 1. 将下一个试管移动到预处理位 * 1. 将下一个试管移动到预处理位
* 2. 如果当前试管是最后一个试管则设置试管架状态为处理完成 * 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() { @Override public Boolean checkCondition() {
/*
*1. 设备工作中
* 1.1 试管架正在处理中
* 1.2 当前Index=-1
*
* 2.1 当前试管处理完成
*
*/
//当前正在工作 //当前正在工作
Boolean cond1 = gstate.isWorking(); 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<A8kPublicResourceType> getDeplyResourceList() { @Override public List<A8kPublicResourceType> getDeplyResourceList() {
return List.of(A8kPublicResourceType.SampleTransferXMotor); return List.of(A8kPublicResourceType.SampleTransferXMotor);
} }

60
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; 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.A8kActionStepType;
import a8k.service.appdevicectrl.action.base.A8kStepAction; import a8k.service.appdevicectrl.action.base.A8kStepAction;
import a8k.service.appstate.AppA8kGStateService; import a8k.service.appstate.AppA8kGStateService;
import a8k.service.appstate.resource.A8kPublicResourceType; import a8k.service.appstate.resource.A8kPublicResourceType;
import a8k.service.appstate.type.state.TubeHolderState; import a8k.service.appstate.type.state.TubeHolderState;
import a8k.service.appstate.type.state.TubeState; import a8k.service.appstate.type.state.TubeState;
import a8k.service.devicedriver.ctrl.SampleScanTransportCtrl;
import a8k.type.exception.AppException; import a8k.type.exception.AppException;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -29,27 +31,55 @@ public class SEQ3_CHECK_THE_QUANTITY_OF_CONSUMABLES extends A8kStepAction {
@Resource @Resource
AppA8kGStateService gstate; AppA8kGStateService gstate;
@PostConstruct
@Resource
SampleScanTransportCtrl sstc;
@Resource
AppProjInfoMgrService projInfoMgrService;
void init() { void init() {
} }
void checkProjResource(Integer projIndex) {
//检查项目ID卡是否存在
// if(projInfoMgrService.)
//检查耗材
//申请耗材
//申请失败抛出异常
//如果出错要归还耗材
}
@Override public void doaction() throws AppException { @Override public void doaction() throws AppException {
//检查孵育盘是否有空位
// if(gstate.getIncubationPlate().getEmptyPos())){
// }
//检查当前试管的待做项目所需要的资源是否充足 //检查当前试管的待做项目所需要的资源是否充足
// List<Integer> 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() { @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<A8kPublicResourceType> getDeplyResourceList() { @Override public List<A8kPublicResourceType> getDeplyResourceList() {
@ -57,6 +87,6 @@ public class SEQ3_CHECK_THE_QUANTITY_OF_CONSUMABLES extends A8kStepAction {
} }
@Override public Boolean isAllowsParallelRunning() { @Override public Boolean isAllowsParallelRunning() {
return false;
return false;//串行任务无需担心状态冲突
} }
} }

28
src/main/java/a8k/service/appstate/AppA8kGStateService.java

@ -1,10 +1,7 @@
package a8k.service.appstate; package a8k.service.appstate;
import a8k.service.appdevicectrl.type.app_consumables_mgr_service.ConsumableState; 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.A8kWorkState;
import a8k.service.appstate.type.state.TubeHolderState; import a8k.service.appstate.type.state.TubeHolderState;
import a8k.type.tube_setting.TubeHolderSetting; import a8k.type.tube_setting.TubeHolderSetting;
@ -29,23 +26,24 @@ public class AppA8kGStateService {
A8kWorkState workState = A8kWorkState.IDLE; // 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<TubeHolderSetting> tubeHolderSettings = new ArrayList<>(); List<TubeHolderSetting> tubeHolderSettings = new ArrayList<>();
//当前正在处理的试管
Tube curProcessingTube = null;
//主流程控制状态 //主流程控制状态
public MainFlowCtrlState mainFlowCtrlState = new MainFlowCtrlState(); public MainFlowCtrlState mainFlowCtrlState = new MainFlowCtrlState();
@ -77,4 +75,12 @@ public class AppA8kGStateService {
return tubeHolder.state; return tubeHolder.state;
} }
synchronized public Tube getCurProcessingTube() {
return curProcessingTube;
}
synchronized public void setCurProcessingTube(Tube tube) {
curProcessingTube = tube;
}
} }

46
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<TubeProcessContext> 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;
}
}

8
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();
}

10
src/main/java/a8k/service/appstate/type/IncubationPlate.java

@ -22,5 +22,15 @@ public class IncubationPlate {
return null; return null;
} }
public Integer getEmptyPosNum() {
Integer num = 0;
for (IncubationSubTank subtank : subtanks) {
if (subtank.state.equals(IncubationSubTankState.EMPTY)) {
num++;
}
}
return num;
}
} }

8
src/main/java/a8k/service/appstate/type/Tube.java

@ -10,7 +10,7 @@ public class Tube {
public String sampleid; //样本ID-系统生成-唯一标识一个样本 public String sampleid; //样本ID-系统生成-唯一标识一个样本
public Boolean isHighTube = false; public Boolean isHighTube = false;
public Boolean isTubeExist = false;
public Boolean isEmergency = false;
public BloodType bloodType = BloodType.WHOLE_BLOOD; //血液类型 public BloodType bloodType = BloodType.WHOLE_BLOOD; //血液类型
public String sampleBarcode = ""; //用于请求用户信息的条码ID public String sampleBarcode = ""; //用于请求用户信息的条码ID
@ -18,5 +18,9 @@ public class Tube {
public List<Integer> projIndex = new ArrayList<>(); //项目代码 public List<Integer> projIndex = new ArrayList<>(); //项目代码
// //
public TubeState state = TubeState.TO_BE_PROCESSED; //样本被处理的状态
public TubeState state = TubeState.EMPTY; //样本被处理的状态
} }

15
src/main/java/a8k/service/appstate/type/TubeHolder.java

@ -1,14 +1,13 @@
package a8k.service.appstate.type; package a8k.service.appstate.type;
import a8k.service.appstate.type.state.TubeHolderState; import a8k.service.appstate.type.state.TubeHolderState;
import a8k.service.appstate.type.state.TubeState;
import a8k.type.type.A8kTubeHolderType; import a8k.type.type.A8kTubeHolderType;
public class TubeHolder { public class TubeHolder {
public A8kTubeHolderType tubeHolderType = A8kTubeHolderType.BloodTube; //试管架类型 public A8kTubeHolderType tubeHolderType = A8kTubeHolderType.BloodTube; //试管架类型
public Tube[] tubes = new Tube[10]; public Tube[] tubes = new Tube[10];
public TubeHolderState state = TubeHolderState.IDLE; //处理状态
public Integer processingTubeIndex = -1; //当前正在被处理的试管索引
public TubeHolderState state = TubeHolderState.IDLE; //处理状态
public TubeHolder() { public TubeHolder() {
for (int i = 0; i < tubes.length; i++) { 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;
} }
} }

18
src/main/java/a8k/service/appstate/type/EmergencyPosRunState.java → src/main/java/a8k/service/appstate/type/TubeProcessContext.java

@ -1,19 +1,21 @@
package a8k.service.appstate.type; package a8k.service.appstate.type;
import a8k.service.appstate.type.state.EmergencySampleState;
import a8k.type.type.BloodType; import a8k.type.type.BloodType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
* 急诊位位置状态
*/
public class EmergencyPosRunState {
public String userid = ""; //用户输入的样本ID不做逻辑只做展示
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 sampleBarcode = ""; //用于请求用户信息的条码ID
public String userid = ""; //用户输入的样本ID不做逻辑只做展示
public List<Integer> projIndex = new ArrayList<>(); //项目代码 public List<Integer> projIndex = new ArrayList<>(); //项目代码
public BloodType bloodType = BloodType.WHOLE_BLOOD; //血型
public EmergencySampleState state = EmergencySampleState.IDLE; //急诊位状态
} }

8
src/main/java/a8k/service/appstate/type/state/EmergencySampleState.java

@ -1,8 +0,0 @@
package a8k.service.appstate.type.state;
public enum EmergencySampleState {
IDLE,//
PENDING,//
PROCESSING,//
FINISHED,//
}

1
src/main/java/a8k/service/appstate/type/state/TubeHolderState.java

@ -3,5 +3,4 @@ package a8k.service.appstate.type.state;
public enum TubeHolderState { public enum TubeHolderState {
IDLE, //没有试管架 IDLE, //没有试管架
PROCESSING, //正在处理试管架 PROCESSING, //正在处理试管架
PROCESS_FINISHED, //试管架处理完成但试管架并没有被取走
} }

6
src/main/java/a8k/service/appstate/type/state/TubeState.java

@ -2,9 +2,13 @@ package a8k.service.appstate.type.state;
public enum TubeState { public enum TubeState {
// //
EMPTY,//
TO_BE_PROCESSED,//待处理 TO_BE_PROCESSED,//待处理
PRE_PROCESSING, //预处理 PRE_PROCESSING, //预处理
PROCESSING,//预处理
PRE_PROCESSED, //预处理结束
PROCESSING,//处理
PROCESSED,//处理完成
POST_PROCESSING, //后处理 POST_PROCESSING, //后处理
POST_PROCESSED, //后处理完成
PROCESS_COMPLETE,//处理完成 PROCESS_COMPLETE,//处理完成
} }

54
src/main/java/a8k/service/devicedriver/ctrl/ConsumablesScanCtrl.java

@ -16,10 +16,26 @@ import org.springframework.stereotype.Component;
@ExtApiTab(cfg = ExtApiTabConfig.HbotControlService) @ExtApiTab(cfg = ExtApiTabConfig.HbotControlService)
public class ConsumablesScanCtrl { 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 = "扫描耗材") @ExtApiFn(name = "扫描耗材")
public ConsumablesScanRawResult doScanConsumablesAction() throws AppException {
public ScanRawResult doScanConsumablesAction() throws AppException {
if (!stateMgrService.isDeviceInited()) { if (!stateMgrService.isDeviceInited()) {
throw new AppException(A8kEcode.DeviceNotInited.index); throw new AppException(A8kEcode.DeviceNotInited.index);
} }
ConsumablesScanRawResult result = new ConsumablesScanRawResult();
ScanRawResult result = new ScanRawResult();
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
int finalI = 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++) { for (int i = 0; i < 6; i++) {
int finalI = 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++) { for (int i = 0; i < 6; i++) {
int finalI = i; int finalI = i;
ar.dosome("扫描耗材-大瓶缓冲液", () -> result.larBSScanResult[finalI] = scanLarBS(finalI));
ar.dosome("扫描耗材-大瓶缓冲液", () -> result.ch[finalI].larBSScanResult = scanLarBS(finalI));
} }
hbotMoveTo(new Pos2d(0, 0)); hbotMoveTo(new Pos2d(0, 0));
@ -89,17 +105,25 @@ public class ConsumablesScanCtrl {
* 清空 result 中的所有\r * 清空 result 中的所有\r
*/ */
for (int i = 0; i < 6; i++) { 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; 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;
}
} }
Loading…
Cancel
Save