Browse Source

优化上报

master
zhaohe 3 weeks ago
parent
commit
d82da14e2d
  1. 11
      pom.xml
  2. 2
      src/main/java/a8k/OS.java
  3. 3
      src/main/java/a8k/app/controler/api/v1/app/state/AppFlagStateMgrController.java
  4. 2
      src/main/java/a8k/app/controler/api/v1/app/state/DeviceStateController.java
  5. 97
      src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java
  6. 78
      src/main/java/a8k/app/factory/BiLisDoubleTrackFrameFactory.java
  7. 1
      src/main/java/a8k/app/interceptor/RefreshAccessInterceptor.java
  8. 258
      src/main/java/a8k/app/service/DeviceVirtualStateMgrService.java
  9. 48
      src/main/java/a8k/app/service/data/AppUserMgrService.java
  10. 7
      src/main/java/a8k/app/service/engineer/state/EngineerModeStateMgrService.java
  11. 4
      src/main/java/a8k/app/service/mainctrl/AppDeviceInitCtrlService.java
  12. 4
      src/main/java/a8k/app/service/module/SamplePreProcessModule.java
  13. 2
      src/main/java/a8k/app/service/setting/AppSettingsMgrService.java
  14. 94
      src/main/java/a8k/app/service/statemgr/AppFlagStateMgr.java
  15. 104
      src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java
  16. 47
      src/main/java/a8k/app/service/statemgr/DeviceWorkStateMgrService.java
  17. 11
      src/main/java/a8k/app/service/statemgr/GStateMgrService.java
  18. 51
      src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgr.java
  19. 14
      src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java
  20. 52
      src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java
  21. 208
      src/main/java/a8k/app/service/statemgr/TubeStateMgr.java
  22. 40
      src/main/java/a8k/app/type/DeviceWarningFlagStateGroup.java
  23. 4
      src/main/java/a8k/app/type/GState.java
  24. 2
      src/main/java/a8k/app/type/a8k/state/Tube.java
  25. 4
      src/main/java/a8k/app/type/a8k/state/TubeHolder.java
  26. 12
      src/main/java/a8k/app/type/appevent/AppLoginEvent.java
  27. 2
      src/main/java/a8k/app/type/lisprotocol/BiLisDoubleTrackFrame.java
  28. 10
      src/main/java/a8k/app/type/lisprotocol/BiLisDoubleTrackFrameBuildContext.java
  29. 22
      src/main/java/a8k/extui/page/debug/P12TueStateDebugPage.java
  30. 88
      src/test/java/a8k/app/factory/BiLisDoubleTrackFrameFactoryTest.java
  31. 34
      代码说明/20240718.txt

11
pom.xml

@ -127,7 +127,16 @@
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.12.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.12.4</version>
</dependency>
</dependencies>

2
src/main/java/a8k/OS.java

@ -93,7 +93,7 @@ public class OS {
static public String getLocalIp() {
if (isRunOnWindows()) {
return "W:0.0.0.0";
return "192.168.8.10";
}
NetworkInterface networkInterface = null;

3
src/main/java/a8k/app/controler/api/v1/app/state/AppFlagStateMgrController.java

@ -2,6 +2,7 @@ package a8k.app.controler.api.v1.app.state;
import a8k.app.service.statemgr.AppFlagStateMgr;
import a8k.app.type.AppFlagKey;
import a8k.app.type.DeviceWarningFlagStateGroup;
import a8k.app.type.ui.ApiRet;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -37,7 +38,7 @@ public class AppFlagStateMgrController {
@Operation(summary = "获取状态")
@PostMapping("/getFlagState")
public ApiRet<AppFlagStateMgr.DeviceWarningFlagStateGroup> getFlagState() {
public ApiRet<DeviceWarningFlagStateGroup> getFlagState() {
return ApiRet.success(appFlagStateMgr.getFlagState());
}

2
src/main/java/a8k/app/controler/api/v1/app/state/DeviceStateController.java

@ -47,7 +47,7 @@ public class DeviceStateController {
@Operation(summary = "获取<试管架>状态")
@PostMapping("/getTubeHolderState")
public ApiRet<TubeHolder> getTubeHolderState() {
return ApiRet.success(tubeStateMgrService.getTubeHolder());
return ApiRet.success(tubeStateMgrService.getTubeHolderState());
}
@Operation(summary = "获取<孵育盘>的状态")

97
src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java

@ -11,7 +11,10 @@ import a8k.app.service.mainctrl.TubeHolderSettingMgrService;
import a8k.app.service.statemgr.*;
import a8k.app.service.background.FrontEndMessageBoxAndEventMgr;
import a8k.app.type.a8k.ConsumableGroup;
import a8k.app.type.appevent.AppEvent;
import a8k.app.type.appevent.AppLoginEvent;
import a8k.app.utils.ZJsonHelper;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
@ -21,6 +24,7 @@ import jakarta.websocket.*;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
@Component
@EnableScheduling
@ -52,7 +56,7 @@ public class AppWebSocketEndpointMgr {
private final AppUserMgrService appUserMgrService;
private final AppDeviceInitCtrlService appDeviceInitCtrlService;
private final PreReactionStateMgr preReactionStateMgr;
final private GStateMgrService gstate;
final private GStateMgrService gStateMgrService;
final private FrontEndMessageBoxAndEventMgr frontEndMessageBoxAndEventMgr;
final private EngineerModeStateMgrService engineerModeStateMgrService;
final private DeviceWorkStateMgrService deviceWorkStateMgrService;
@ -61,32 +65,28 @@ public class AppWebSocketEndpointMgr {
final private OptScanModuleStateMgr optScanModuleStateMgr;
final private ConsumablesMgrService consumablesMgrService;
final private TubeHolderSettingMgrService tubeHolderSettingMgrService;
final private AppEventBusService appEventBusService;
final private AppFlagStateMgr appFlagStateMgrService;
final private AppEventBusService appEventBusService;
final private AppFlagStateMgr appFlagStateMgrService;
final private AppEventBusService eventBus;
List<Session> stateWebsocketSessions = new ArrayList<>();
List<Session> eventWebsocketSessions = new ArrayList<>();
Thread workThread;
Boolean newStateSession = false;
Map<String, Integer> stateVersionCache = new HashMap<>();
final Object sessionLock = new Object();
synchronized void setNewStateSession() {
this.newStateSession = true;
}
AtomicInteger forceUpdateCnt = new AtomicInteger(0);
synchronized Boolean getAndClearNewStateSession() {
Boolean ret = this.newStateSession;
this.newStateSession = false;
return ret;
}
synchronized public void pushStateWebsocketSession(Session session) {
stateWebsocketSessions.add(session);
setNewStateSession();
forceUpdateCnt.incrementAndGet();
}
synchronized public void removeStateWebsocketSession(Session session) {
stateWebsocketSessions.remove(session);
synchronized (sessionLock) {
stateWebsocketSessions.remove(session);
}
}
synchronized public void pushEventWebsocketSession(Session session) {
@ -140,10 +140,19 @@ public class AppWebSocketEndpointMgr {
broadcastEvent(message);
}
@PostConstruct
void init() {
eventBus.regListener((AppEvent event) -> {
if (event instanceof AppLoginEvent) {
forceUpdateCnt.incrementAndGet();
}
});
}
//
// Scheduled tasks
//
@Scheduled(fixedDelay = 100)
public void reportEvent() {
frontEndMessageBoxAndEventMgr.pollAllAppEvents().forEach(event -> {
@ -152,26 +161,39 @@ public class AppWebSocketEndpointMgr {
}
@Scheduled(fixedDelay = 200)
@Scheduled(fixedDelay = 900)
public void reportDeviceState() {
//TODO : 这里可以考虑增加一个状态版本号只有状态变化时才发送
reportState("DeviceWorkState", deviceWorkStateMgrService.getDeviceWorkState());
reportState("TubeHolderState", tubeStateMgrService.getTubeHolder());
reportState("GDeviceState", gStateMgrService.getGState());
reportState("IncubationPlateState", incubationPlateStateMgr.get());
reportState("OptScanModuleState", optScanModuleStateMgr.getOptScanModule());
reportState("EmergencyPosState", tubeStateMgrService.getEmergencyPosRunState());
reportState("SensorState", gstate.getSensorState());
reportState("ConsumablesState", consumablesMgrService.getState());
reportState("GDeviceState", gstate.getGState());
reportState("EngineerModeState", engineerModeStateMgrService.getState());
reportState("SensorState", gStateMgrService.getSensorState());
DeviceContext deviceContext = new DeviceContext();
deviceContext.runMode = gStateMgrService.getDeviceRunMode();
deviceContext.loginFlag = appUserMgrService.getLoginUsr() != null;
deviceContext.loginUser = appUserMgrService.getLoginUsr();
deviceContext.deviceInitedFlag = appDeviceInitCtrlService.getState().deviceInited;
deviceContext.fatalErrorFlag = deviceWorkStateMgrService.getDeviceWorkState().fatalErrorFlag;
reportState("DeviceContext", deviceContext);
}
@Scheduled(fixedDelay = 30)
@Scheduled(fixedDelay = 100)
public void quickReportStateSchedule() {
quickReportStateSchedule(false);
}
public void quickReportStateSchedule(boolean force) {
reportState("EngineerModeState", engineerModeStateMgrService.getVersion(), force,
engineerModeStateMgrService::getState);
reportState("TubeHolderState", tubeStateMgrService.getVersion(), force, tubeStateMgrService::getTubeHolderState);
reportState("EmergencyPosState", tubeStateMgrService.getVersion(), force, tubeStateMgrService::getEmergencyPosRunState);
reportState("OptScanModuleState", optScanModuleStateMgr.getStateVersion(), force,
optScanModuleStateMgr::getOptScanModule);
reportState("DeviceWorkState", deviceWorkStateMgrService.getVersion(), force,
deviceWorkStateMgrService::getDeviceWorkState);
reportState("TubeHolderSetting", tubeHolderSettingMgrService.getTubeHolderSettingVersion(), force,
tubeHolderSettingMgrService::getTubeHolderSettings);
reportState("AppFlagStateList", appFlagStateMgrService.getStateVersion(), force,
@ -195,24 +217,21 @@ public class AppWebSocketEndpointMgr {
}
@Scheduled(fixedDelay = 1000)
public void reportSessionState() {
DeviceContext deviceContext = new DeviceContext();
deviceContext.runMode = gstate.getDeviceRunMode();
deviceContext.loginFlag = appUserMgrService.getLoginUsr() != null;
deviceContext.loginUser = appUserMgrService.getLoginUsr();
deviceContext.deviceInitedFlag = appDeviceInitCtrlService.getState().deviceInited;
deviceContext.fatalErrorFlag = deviceWorkStateMgrService.getDeviceWorkState().fatalErrorFlag;
reportState("DeviceContext", deviceContext);
}
Boolean isForceUpdateNow() {
if (forceUpdateCnt.get() != 0) {
forceUpdateCnt.getAndDecrement();
return true;
}
return false;
}
@Scheduled(fixedDelay = 30)
public void onNewStateSession() {
if (getAndClearNewStateSession()) {
if (isForceUpdateNow()) {
log.info("onNewStateSession: new state session detected, broadcasting current state");
reportDeviceState();
reportSessionState();
quickReportStateSchedule(true);
}
}

78
src/main/java/a8k/app/factory/BiLisDoubleTrackFrameFactory.java

@ -3,6 +3,7 @@ package a8k.app.factory;
import a8k.app.constant.AppConstant;
import a8k.app.dao.type.db.ReactionRecord;
import a8k.app.type.lisprotocol.BiLisDoubleTrackFrame;
import a8k.app.type.lisprotocol.BiLisDoubleTrackFrameBuildContext;
import a8k.app.type.lisprotocol.BiLisFrameParseErrorCode;
import a8k.app.type.lisprotocol.BiLisFrameParseException;
import a8k.app.utils.ByteArrayUtils;
@ -14,11 +15,13 @@ import java.lang.reflect.Field;
@Slf4j
public class BiLisDoubleTrackFrameFactory {
//
static public BiLisDoubleTrackFrame.RFrame createRFrame(ReactionRecord reactionRecord, Integer subProjIndex) {
static public BiLisDoubleTrackFrameBuildContext createRFrame(ReactionRecord reactionRecord, Integer subProjIndex) {
//R|A10|123456789|^PCT/CRP^CRP^#|46|mg/L|0.5-200||L_1^_03|F||||20141201144906||0|<CR>
BiLisDoubleTrackFrameBuildContext buildContext = new BiLisDoubleTrackFrameBuildContext();
BiLisDoubleTrackFrame frame = new BiLisDoubleTrackFrame();
BiLisDoubleTrackFrame.RFrame rFrame = new BiLisDoubleTrackFrame.RFrame();
Double rawResultVal = reactionRecord.results.get(subProjIndex).result;
@ -66,17 +69,32 @@ public class BiLisDoubleTrackFrameFactory {
rFrame.pid = reactionRecord.sampleUserid;
rFrame.sampleType = sampleType;//样本类型
return rFrame;
frame.frameType = BiLisDoubleTrackFrame.STX;
frame.frameContent = rFrame;
buildContext.frame = frame;
serialize(buildContext, frame);
return buildContext;
}
static public byte[] createRFrameBytes(BiLisDoubleTrackFrame.RFrame rFrame) {
BiLisDoubleTrackFrame frame = new BiLisDoubleTrackFrame();
static public BiLisDoubleTrackFrameBuildContext createQFrameBytes(String deviceName, String barcode) {
BiLisDoubleTrackFrameBuildContext context = new BiLisDoubleTrackFrameBuildContext();
BiLisDoubleTrackFrame frame = new BiLisDoubleTrackFrame();
BiLisDoubleTrackFrame.QFrame qFrame = new BiLisDoubleTrackFrame.QFrame();
frame.frameType = BiLisDoubleTrackFrame.STX;
frame.frameContent = rFrame;
return serialize(frame);
qFrame.type = "Q"; // 请求类型
qFrame.deviceName = deviceName;
qFrame.barcode = String.format("^%s", barcode); // 条形码,^开头
frame.frameContent = qFrame;
context.frame = frame;
serialize(context, frame);
return context;
}
static public BiLisDoubleTrackFrame createOFrame(byte[] rxData) throws BiLisFrameParseException {
/*
* Frame Structure:
@ -89,7 +107,7 @@ public class BiLisDoubleTrackFrameFactory {
throw new BiLisFrameParseException(BiLisFrameParseErrorCode.FrameLengthTooShort, "rx packet length is too short: " + rxData.length);
}
byte stx = rxData[0];
byte fn = rxData[1];
char fn = (char) rxData[1];
byte etx = rxData[rxData.length - 5];
byte c1 = rxData[rxData.length - 4];
byte c2 = rxData[rxData.length - 3];
@ -158,39 +176,29 @@ public class BiLisDoubleTrackFrameFactory {
}
static public byte[] createQFrameBytes(String deviceName, String barcode) {
BiLisDoubleTrackFrame frame = new BiLisDoubleTrackFrame();
BiLisDoubleTrackFrame.QFrame qFrame = new BiLisDoubleTrackFrame.QFrame();
frame.frameType = BiLisDoubleTrackFrame.STX;
qFrame.type = "Q"; // 请求类型
qFrame.deviceName = deviceName;
qFrame.barcode = String.format("^%s", barcode); // 条形码,^开头
frame.frameContent = qFrame;
return serialize(frame);
}
static public byte[] serialize(BiLisDoubleTrackFrame frame) {
static public void serialize(BiLisDoubleTrackFrameBuildContext buildContext, BiLisDoubleTrackFrame frame) {
/*
* Frame Structure:
* STX,FN,Content,ETX,C1,C2,CR,LF
*/
if (frame.frameType != BiLisDoubleTrackFrame.STX) {
log.warn("Frame type is not STX, cannot serialize: {}", frame.frameType);
return new byte[0];
buildContext.buildSuccess = false;
}
if ((frame.frameContent instanceof BiLisDoubleTrackFrame.QFrame
|| frame.frameContent instanceof BiLisDoubleTrackFrame.RFrame
)) {
String frameContent = serializeFrameContent(frame.frameContent);
return ByteArrayUtils.toByteArray(createBiLisDoubleTrackFrame(frameContent));
String content = serializeFrameContent(frame.frameContent);
buildContext.frameContentStr = content;
createBiLisDoubleTrackFrame(buildContext, content);
} else {
log.warn("Unsupported frame content type: {}", frame.frameContent.getClass().getSimpleName());
return new byte[0];
buildContext.buildSuccess = false;
}
}
private static ByteBuf createBiLisDoubleTrackFrame(String content) {
private static void createBiLisDoubleTrackFrame(BiLisDoubleTrackFrameBuildContext context, String content) {
char[] checksum = computeChecksum(content);
ByteBuf byteBuf = io.netty.buffer.Unpooled.buffer(BiLisDoubleTrackFrame.PACKET_MAX_LENGTH);
byteBuf.writeByte(BiLisDoubleTrackFrame.STX);
@ -201,10 +209,12 @@ public class BiLisDoubleTrackFrameFactory {
byteBuf.writeByte(checksum[1]);
byteBuf.writeByte(BiLisDoubleTrackFrame.CR);
byteBuf.writeByte(BiLisDoubleTrackFrame.LF);
return byteBuf;
context.frameBytes = ByteArrayUtils.toByteArray(byteBuf);
context.checksum = checksum;
}
private static String serializeFrameContent(Object obj) {
public static String serializeFrameContent(Object obj) {
StringBuilder sb = new StringBuilder();
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
@ -229,7 +239,7 @@ public class BiLisDoubleTrackFrameFactory {
return removeTrailingPipes(sb.toString());
}
private static String removeTrailingPipes(String str) {
public static String removeTrailingPipes(String str) {
// 去除末尾的换行符和回车符
str = str.trim();
// 从字符串末尾开始检查连续的|字符
@ -246,21 +256,23 @@ public class BiLisDoubleTrackFrameFactory {
return str + "\r";
}
private static char[] computeChecksum(String content) {
public static char[] computeChecksum(String content) {
int checksum = 0;
checksum += BiLisDoubleTrackFrame.FN;
checksum += BiLisDoubleTrackFrame.ETX;
if (content != null) {
for (char c : content.toCharArray()) {
checksum += c;
}
}
checksum += BiLisDoubleTrackFrame.ETX;
checksum += BiLisDoubleTrackFrame.FN;
checksum = checksum % 256; // 取模运算确保checksum在0-255范围内
//C1高4位,C2低4位
return intToHexChars(checksum);
}
private static char[] intToHexChars(int value) {
public static char[] intToHexChars(int value) {
// 将整数转换为两个十六进制字符 ret (0-9,a-f)
char[] hexChars = new char[2];
hexChars[0] = Character.forDigit((value >> 4) & 0x0F, 16); // 高4位
@ -274,7 +286,7 @@ public class BiLisDoubleTrackFrameFactory {
return hexChars;
}
static private String strArraySafeGet(String[] list, int index) {
static public String strArraySafeGet(String[] list, int index) {
if (list == null || index < 0 || index >= list.length) {
return "";
}

1
src/main/java/a8k/app/interceptor/RefreshAccessInterceptor.java

@ -21,7 +21,6 @@ public class RefreshAccessInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) {
userMgr.recordAccess();
return true;
}
}

258
src/main/java/a8k/app/service/DeviceVirtualStateMgrService.java

@ -0,0 +1,258 @@
package a8k.app.service;
import a8k.app.channel.iflytophald.type.protocol.A8kEcode;
import a8k.app.constant.AppConstant;
import a8k.app.factory.FakeA8kConsumableContainerFactory;
import a8k.app.factory.FakeAppErrorFactory;
import a8k.app.factory.ZAppPromptFactory;
import a8k.app.service.utils.ProjInfoUtils;
import a8k.app.type.AppFlagKey;
import a8k.app.type.DeviceWarningFlagStateGroup;
import a8k.app.type.PreReactionGrid;
import a8k.app.type.PreReactionGridGroup;
import a8k.app.type.a8k.BloodType;
import a8k.app.type.a8k.ConsumableGroup;
import a8k.app.type.a8k.LittleBottleConsumableType;
import a8k.app.type.a8k.proj.ProjBriefInfo;
import a8k.app.type.a8k.state.*;
import a8k.app.type.a8k.state.enumtype.IncubationSubTankState;
import a8k.app.type.a8k.state.enumtype.TubeHolderState;
import a8k.app.type.a8k.state.enumtype.TubeState;
import a8k.app.type.error.AppError;
import a8k.app.utils.ZList;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
@RequiredArgsConstructor
@Slf4j
public class DeviceVirtualStateMgrService {
/**
* 获取虚拟孵育盘状态
* @return 虚拟孵育盘状态
*/
synchronized public IncubationPlate getVirtualIncubationPlateState() {
IncubationPlate incubationPlate = new IncubationPlate();
int i = 0;
for (IncubationSubTank subtank : incubationPlate.subtanks) {
i++;
switch (i) {
case 1 -> subtank.state = IncubationSubTankState.RESERVED;
case 2 -> subtank.state = IncubationSubTankState.WAITING_FOR_DROP;
case 3 -> subtank.state = IncubationSubTankState.INCUBATING;
case 4 -> subtank.state = IncubationSubTankState.ERROR;
case 5 -> subtank.state = IncubationSubTankState.INCUBATION_COMPLETE;
default -> subtank.state = IncubationSubTankState.EMPTY;
}
subtank.sampleInfo = new SampleInfo(
"250109_001E01", 0, false, false, BloodType.WHOLE_BLOOD, "B3A7KK8DKF", "250109_001E"
);
subtank.sampleInfo.bloodType = BloodType.WHOLE_BLOOD;
subtank.sampleInfo.sampleBarcode = "112334455667";
subtank.sampleInfo.userid = "250109_001E";
subtank.projInfo = new ProjBriefInfo();
subtank.projInfo.projId = 1;
subtank.projInfo.projName = "hsCRP";
subtank.projInfo.projShortName = "CA";
subtank.projInfo.color = "#DC143C";
subtank.sampleInfo.sampleId = "250109_001E01";
subtank.projId = 1;
subtank.lotId = "CA123456";
subtank.isEmergency = i == 2;
if (subtank.state.equals(IncubationSubTankState.ERROR)) {
subtank.error = new AppError(A8kEcode.PROJ_CARD_ERROR_WRONG_UNSUPPORTED, "");
subtank.errorInfo = ZAppPromptFactory.buildAppPrompt(subtank.error);
}
subtank.startIncubatedTime = new Date().getTime();
subtank.incubatedTimeSec = 3 * 60;
subtank.remainTimeSec = 3 * 60;
}
return incubationPlate;
}
static void addProjInfoToTube(Tube tube, Integer projId) {
ProjBriefInfo projBriefInfo = FakeA8kConsumableContainerFactory.buildFakeProjBriefInfo(projId);
tube.getProjInfo().add(projBriefInfo);
tube.getProjIds().add(projBriefInfo.projId);
}
static Tube createFakeTube(Integer pos) {
Tube tube = new Tube(pos);
tube.setSampleId("250109_001E0" + pos);
tube.setBloodType(BloodType.WHOLE_BLOOD);
tube.setSampleBarcode("112334455667");
tube.setUserid(String.format("250109_%dE", pos));
switch (pos) {
case 1 -> tube.setState(TubeState.EMPTY);
case 2 -> {
tube.setState(TubeState.ERROR);
tube.setError(FakeAppErrorFactory.buildAEConsumeNotEnoughError());
tube.setErrorInfo(ZAppPromptFactory.buildAppPrompt(tube.getError()));
addProjInfoToTube(tube, 1);
addProjInfoToTube(tube, 2);
}
case 3, 4, 5, 6 -> {
tube.setState(TubeState.PROCESS_COMPLETE);
addProjInfoToTube(tube, 1);
addProjInfoToTube(tube, 2);
addProjInfoToTube(tube, 3);
}
case 7 -> {
tube.setState(TubeState.PROCESSING);
addProjInfoToTube(tube, 1);
addProjInfoToTube(tube, 2);
addProjInfoToTube(tube, 3);
}
case 8, 9, 10 -> {
tube.setState(TubeState.TO_BE_PROCESSED);
addProjInfoToTube(tube, 1);
addProjInfoToTube(tube, 2);
}
}
tube.setIsHighTube(pos % 2 == 0); //假设偶数位置为高位管
return tube;
}
public TubeHolder getVirtualTubeHolderState() {
TubeHolder tubeHolder = new TubeHolder();
tubeHolder.setTubes(new Tube[]{
createFakeTube(1),
createFakeTube(2),
createFakeTube(3),
createFakeTube(4),
createFakeTube(5),
createFakeTube(6),
createFakeTube(7),
createFakeTube(8),
createFakeTube(9),
createFakeTube(10)
});
tubeHolder.setState(TubeHolderState.PROCESSING);
return tubeHolder;
}
public EmergencyTubePos getVirtualEmergencyTube() {
var tubePosState = new EmergencyTubePos();
tubePosState.tube = createFakeTube(0);
tubePosState.tube.setPos(0);
tubePosState.tube.setIsEmergency(true);
return tubePosState;
}
public PreReactionGridGroup getFakePreReactionGridGroup(ConsumableGroup group) {
PreReactionGridGroup gridGroup = new PreReactionGridGroup(group);
gridGroup.group = group;
if (group.off % 2 == 0) {
gridGroup.installed = true;
gridGroup.hasSomeGridInReacting = true;
gridGroup.hasSomeGridReactedCompleted = true;
} else {
gridGroup.installed = false;
gridGroup.hasSomeGridInReacting = false;
gridGroup.hasSomeGridReactedCompleted = false;
}
gridGroup.consumableType = LittleBottleConsumableType.BufferSolution;
var projBuildInInfo = FakeA8kConsumableContainerFactory.buildFakeProjBuildInInfo(group.off);
gridGroup.projBriefInfo = ProjInfoUtils.buildProjBrefInfo(projBuildInInfo);
gridGroup.version = 10;
for (int i = 0; i < AppConstant.CONSUMABLE_NUM; i++) {
gridGroup.grids.get(i).projId = projBuildInInfo.projId;
gridGroup.grids.get(i).projBuildinInfo = projBuildInInfo;
gridGroup.grids.get(i).projExtInfoCard = null;
switch (i / 5) {
case 0 -> {
gridGroup.grids.get(i).state = PreReactionGrid.State.UNINSTALL;
}
case 1 -> {
gridGroup.grids.get(i).state = PreReactionGrid.State.USED;
}
case 2 -> {
gridGroup.grids.get(i).state = PreReactionGrid.State.REACTION_COMPLETED;
gridGroup.grids.get(i).sampleInfo.userid = "UID123";
}
case 3 -> {
gridGroup.grids.get(i).state = PreReactionGrid.State.REACTING;
gridGroup.grids.get(i).sampleInfo.userid = "UID123";
gridGroup.grids.get(i).reactionRemainingTime = 3 * 60L;
}
case 4 -> {
gridGroup.grids.get(i).state = PreReactionGrid.State.TO_BE_USED;
}
}
}
return gridGroup;
}
public SensorState getVirtualSensorState() {
SensorState sensorState = new SensorState();
sensorState.setPboxTemperature(24);
sensorState.setIncubateBoxTemperature(25);
sensorState.setWasteBinFullFlag(false);
return sensorState;
}
//
// VIRTUAL_OPERATION
//
public DeviceWarningFlagStateGroup getDeviceFlagStateVirtualStateInitVal(DeviceWarningFlagStateGroup deviceWarningFlagState) {
DeviceWarningFlagStateGroup virtualWarningState = ObjectUtil.clone(deviceWarningFlagState); //初始化时复制一份状态版本号
virtualWarningState.version = 10000;
//设置VirtualState初始值
var consumeNotEnoughState = virtualWarningState.find(AppFlagKey.ConsumeNotEnoughState);
consumeNotEnoughState.state = true; //
consumeNotEnoughState.errorDetailInfo = FakeAppErrorFactory.buildAEConsumeNotEnoughError();
consumeNotEnoughState.errorPromptInfo = ZAppPromptFactory.buildAppPrompt(consumeNotEnoughState.errorDetailInfo);
var tipNotEnoughState = virtualWarningState.find(AppFlagKey.TipNotEnoughState);
tipNotEnoughState.state = true; //
tipNotEnoughState.errorDetailInfo = FakeAppErrorFactory.buildError(A8kEcode.APPE_TIP_NOT_ENOUGH);
tipNotEnoughState.errorPromptInfo = ZAppPromptFactory.buildAppPrompt(tipNotEnoughState.errorDetailInfo);
var infeedExceptionState = virtualWarningState.find(AppFlagKey.InfeedExceptionState);
infeedExceptionState.state = true; //
infeedExceptionState.errorDetailInfo = FakeAppErrorFactory.buildAEHardwareError();
infeedExceptionState.errorPromptInfo = ZAppPromptFactory.buildAppPrompt(infeedExceptionState.errorDetailInfo);
var outfeedAreaFullState = virtualWarningState.find(AppFlagKey.OutfeedAreaFullState);
outfeedAreaFullState.state = true; //
outfeedAreaFullState.errorDetailInfo = FakeAppErrorFactory.buildError(A8kEcode.APPE_OUTFEED_AREA_IS_FULL);
outfeedAreaFullState.errorPromptInfo = ZAppPromptFactory.buildAppPrompt(outfeedAreaFullState.errorDetailInfo);
var wasteBinFullState = virtualWarningState.find(AppFlagKey.WasteBinFull);
wasteBinFullState.state = true; //
wasteBinFullState.errorDetailInfo = FakeAppErrorFactory.buildError(A8kEcode.APPE_WAST_BIN_IS_FULL);
wasteBinFullState.errorPromptInfo = ZAppPromptFactory.buildAppPrompt(wasteBinFullState.errorDetailInfo);
if (AppFlagKey.InfeedPPSFlag.enabled)
virtualWarningState.find(AppFlagKey.InfeedPPSFlag).state = true; //入料区光电
if (AppFlagKey.OutfeedPPSFlag.enabled)
virtualWarningState.find(AppFlagKey.OutfeedPPSFlag).state = false; //入料区光电
if (AppFlagKey.TubeholderChannelPPSFlag.enabled)
virtualWarningState.find(AppFlagKey.TubeholderChannelPPSFlag).state = true; //入料区光电
if (AppFlagKey.PlateBoxLidPPSState.enabled)
virtualWarningState.find(AppFlagKey.PlateBoxLidPPSState).state = false; //入料区光电
return virtualWarningState;
}
}

48
src/main/java/a8k/app/service/data/AppUserMgrService.java

@ -5,9 +5,12 @@ import a8k.app.dao.DeviceSettingDao;
import a8k.app.dao.type.db.AppUser;
import a8k.app.dao.type.db.DeviceSetting;
import a8k.app.channel.iflytophald.type.protocol.A8kEcode;
import a8k.app.service.background.AppEventBusService;
import a8k.app.type.appevent.AppLoginEvent;
import a8k.app.type.exception.AppException;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;
@ -19,33 +22,19 @@ import java.util.List;
@Component
@EnableScheduling //Enable scheduled tasks
@RequiredArgsConstructor
public class AppUserMgrService {
static Logger logger = org.slf4j.LoggerFactory.getLogger(AppUserMgrService.class);
/**
* current user
*/
@Resource
AppUsrDao appUsrDao;
@Resource
DeviceSettingDao deviceSettingDao;
private final AppUsrDao appUsrDao;
private final DeviceSettingDao deviceSettingDao;
private final AppEventBusService appEventBusService;
AppUser loginUsr = null;
/**
* timestamp of last access
*/
private volatile Instant lastAccess;
/**
* auto logout time out duration
*/
private volatile Duration autoLogoutTimeout;
/**
* flag to enable auto logout
*/
private volatile boolean autoLogout;
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// EXT FUNC
@ -58,9 +47,7 @@ public class AppUserMgrService {
public void init() {
DeviceSetting deviceSetting = deviceSettingDao.get();
int minutes = deviceSetting.getAutoLogoutTimeout();
this.autoLogoutTimeout = Duration.ofMinutes(minutes);
boolean autoLogout = deviceSetting.getAutoLogout();
this.autoLogout = autoLogout;
boolean autoLogout = deviceSetting.getAutoLogout();
logger.debug("initialized autoLogout={}, timeout={} minutes", autoLogout, minutes);
}
@ -74,6 +61,7 @@ public class AppUserMgrService {
throw new AppException(A8kEcode.USR_PASSWORD_ERROR);
}
loginUsr = usr;
appEventBusService.pushEvent(new AppLoginEvent(usr));
return (usr);
}
@ -87,22 +75,6 @@ public class AppUserMgrService {
/**
* refresh lastAccess on each intercepted request
*/
public synchronized void recordAccess() {
if (loginUsr != null) {
this.lastAccess = Instant.now();
}
}
public synchronized void updateAutoLogout(boolean autoLogout) {
this.autoLogout = autoLogout;
logger.debug("updated cache autoLogout:{}", autoLogout);
}
public synchronized void updateAutoLogoutTimeout(int autoLogoutTimeout) {
this.autoLogoutTimeout = Duration.ofMinutes(autoLogoutTimeout);
logger.debug("updated cache autoLogoutTimeout {} minutes", autoLogoutTimeout);
}
synchronized public AppUser getLoginUsr() {
return (loginUsr);
@ -119,7 +91,6 @@ public class AppUserMgrService {
return (appUsrDao.getAllUsr());
}
public AppUser addUser(String account, String password, AppUser.UsrRole type) throws AppException {
var user = appUsrDao.getUsrByAccount(account);
if (user != null) {
@ -130,7 +101,6 @@ public class AppUserMgrService {
return appUsrDao.getUsrByAccount(account);
}
public Void delUser(Integer id) {
appUsrDao.deleteUserById(id);
return null;

7
src/main/java/a8k/app/service/engineer/state/EngineerModeStateMgrService.java

@ -13,12 +13,19 @@ import org.springframework.stereotype.Component;
public class EngineerModeStateMgrService {
EngineerModeState state = new EngineerModeState();
Integer version = 0;
synchronized public EngineerModeState getState() {
return state;
}
synchronized public Integer getVersion() {
return version;
}
synchronized public void setEngineerWorkState(EngineerWorkState engineerWorkState) {
state.engineerWorkState = engineerWorkState;
version++;
}

4
src/main/java/a8k/app/service/mainctrl/AppDeviceInitCtrlService.java

@ -31,6 +31,7 @@ import java.util.List;
@RequiredArgsConstructor
public class AppDeviceInitCtrlService {
private final AppEventBusService appEventBusService;
private final GStateMgrService gStateMgrService;
public static class Checkpoint {
public enum Type {
@ -238,6 +239,9 @@ public class AppDeviceInitCtrlService {
if (virtualDevice.isEnable()) {
virtualDevice.doVirtualThings("初始化设备");
gstate.setDeviceInited(true);
return results;
}

4
src/main/java/a8k/app/service/module/SamplePreProcessModule.java

@ -245,7 +245,7 @@ public class SamplePreProcessModule {
actionTaskPool.pushTask(TaskLine.SamplePrepare, () -> {
Tube tube = tubeStateMgrService.getCurProcessingTube();
TubeHolder tubeHolder = tubeStateMgrService.getTubeHolder();
TubeHolder tubeHolder = tubeStateMgrService.getTubeHolderState();
Boolean isHighTube = tube.getIsHighTube();
/*
* 样本预处理包括脱帽盖帽摇匀
@ -281,7 +281,7 @@ public class SamplePreProcessModule {
//
// 取样本到小缓冲瓶或者探测物质中进行反应
//
TubeHolder tubeHolder = tubeStateMgrService.getTubeHolder();
TubeHolder tubeHolder = tubeStateMgrService.getTubeHolderState();
Tube tube = tubeStateMgrService.getCurProcessingTube();
A8kSamplePos samplePos = ProjectParamUtils.getSamplePos(tubeHolder, tube);
List<ProjectPreProcessContext> cxts = tube.getPreProcessContexts();

2
src/main/java/a8k/app/service/setting/AppSettingsMgrService.java

@ -72,14 +72,12 @@ public class AppSettingsMgrService {
DeviceSetting setting = deviceSettingDao.get();
setting.autoLogoutTimeout = val;
deviceSettingDao.update(setting);
appUserMgrService.updateAutoLogoutTimeout(val);
}
public void setAutoLogout(Boolean val) {
DeviceSetting setting = deviceSettingDao.get();
setting.autoLogout = val;
deviceSettingDao.update(setting);
appUserMgrService.updateAutoLogout(val);
}

94
src/main/java/a8k/app/service/statemgr/AppFlagStateMgr.java

@ -1,13 +1,13 @@
package a8k.app.service.statemgr;
import a8k.app.factory.FakeAppErrorFactory;
import a8k.app.factory.ZAppPromptFactory;
import a8k.app.channel.iflytophald.type.protocol.A8kEcode;
import a8k.app.i18n.Internationalization;
import a8k.app.service.DeviceVirtualStateMgrService;
import a8k.app.type.AppFlagKey;
import a8k.app.type.AppFlagType;
import a8k.app.type.DeviceRunMode;
import a8k.app.type.DeviceWarningFlagStateGroup;
import a8k.app.type.error.AppError;
import a8k.app.type.ui.ZAppPromopt;
import a8k.app.utils.ZJsonHelper;
@ -17,8 +17,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Component
@ -26,6 +24,8 @@ import java.util.Objects;
@RequiredArgsConstructor
public class AppFlagStateMgr {
private final DeviceVirtualStateMgrService deviceVirtualStateMgrService;
static public class AppFlagState implements java.io.Serializable {
public boolean state;
public AppFlagType flagType;
@ -47,40 +47,6 @@ public class AppFlagStateMgr {
}
}
static public class DeviceWarningFlagStateGroup implements java.io.Serializable {
public List<AppFlagState> states = new ArrayList<>();
public Integer version = 0; //状态版本号
// 别删,被前端使用
public Boolean isHasWarningTriggerFlag() {
for (AppFlagState state : states) {
if (state.flagType.equals(AppFlagType.WarningFlag) && state.state) {
return true; //如果有任意一个状态为true,则返回true
}
}
return false; //如果没有任意一个状态为true,则返回false
}
public Boolean isHasErrorTriggerFlag() {
for (AppFlagState state : states) {
if (state.flagType.equals(AppFlagType.ErrorFlag) && state.state) {
return true; //如果有任意一个状态为true,则返回true
}
}
return false; //如果没有任意一个状态为true,则返回false
}
public AppFlagState find(AppFlagKey appFlagKey) {
for (AppFlagState state : states) {
if (state.keyName.equals(appFlagKey)) {
return state;
}
}
log.error("find: Unknown DeviceWarningFlagState: {}", appFlagKey.name());
return null; //如果没有找到,返回null
}
}
private final GStateMgrService gstate;
@ -97,13 +63,12 @@ public class AppFlagStateMgr {
deviceWarningFlagState.states.add(new AppFlagState(flagKey, flagKey.flagType));
}
lastCpyDeviceWarningFlagState = ObjectUtil.clone(deviceWarningFlagState); //初始化时复制一份状态
initVirtualState();
virtualWarningState = deviceVirtualStateMgrService.getDeviceFlagStateVirtualStateInitVal(deviceWarningFlagState);
}
synchronized public DeviceWarningFlagStateGroup getFlagState() {
if (gstate.isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
log.info("virtualWarningState: {}", ZJsonHelper.objectToJson(virtualWarningState));
// log.info("virtualWarningState: {}", ZJsonHelper.objectToJson(virtualWarningState));
return virtualWarningState;
}
//
@ -228,51 +193,8 @@ public class AppFlagStateMgr {
return true;
}
//
// VIRTUAL_OPERATION
//
private void initVirtualState() {
virtualWarningState = ObjectUtil.clone(deviceWarningFlagState); //初始化时复制一份状态版本号
virtualWarningState.version = 10000;
//设置VirtualState初始值
var consumeNotEnoughState = virtualWarningState.find(AppFlagKey.ConsumeNotEnoughState);
consumeNotEnoughState.state = true; //
consumeNotEnoughState.errorDetailInfo = FakeAppErrorFactory.buildAEConsumeNotEnoughError();
consumeNotEnoughState.errorPromptInfo = ZAppPromptFactory.buildAppPrompt(consumeNotEnoughState.errorDetailInfo);
var tipNotEnoughState = virtualWarningState.find(AppFlagKey.TipNotEnoughState);
tipNotEnoughState.state = true; //
tipNotEnoughState.errorDetailInfo = FakeAppErrorFactory.buildError(A8kEcode.APPE_TIP_NOT_ENOUGH);
tipNotEnoughState.errorPromptInfo = ZAppPromptFactory.buildAppPrompt(tipNotEnoughState.errorDetailInfo);
var infeedExceptionState = virtualWarningState.find(AppFlagKey.InfeedExceptionState);
infeedExceptionState.state = true; //
infeedExceptionState.errorDetailInfo = FakeAppErrorFactory.buildAEHardwareError();
infeedExceptionState.errorPromptInfo = ZAppPromptFactory.buildAppPrompt(infeedExceptionState.errorDetailInfo);
var outfeedAreaFullState = virtualWarningState.find(AppFlagKey.OutfeedAreaFullState);
outfeedAreaFullState.state = true; //
outfeedAreaFullState.errorDetailInfo = FakeAppErrorFactory.buildError(A8kEcode.APPE_OUTFEED_AREA_IS_FULL);
outfeedAreaFullState.errorPromptInfo = ZAppPromptFactory.buildAppPrompt(outfeedAreaFullState.errorDetailInfo);
var wasteBinFullState = virtualWarningState.find(AppFlagKey.WasteBinFull);
wasteBinFullState.state = true; //
wasteBinFullState.errorDetailInfo = FakeAppErrorFactory.buildError(A8kEcode.APPE_WAST_BIN_IS_FULL);
wasteBinFullState.errorPromptInfo = ZAppPromptFactory.buildAppPrompt(wasteBinFullState.errorDetailInfo);
if (AppFlagKey.InfeedPPSFlag.enabled)
virtualWarningState.find(AppFlagKey.InfeedPPSFlag).state = true; //入料区光电
if (AppFlagKey.OutfeedPPSFlag.enabled)
virtualWarningState.find(AppFlagKey.OutfeedPPSFlag).state = false; //入料区光电
if (AppFlagKey.TubeholderChannelPPSFlag.enabled)
virtualWarningState.find(AppFlagKey.TubeholderChannelPPSFlag).state = true; //入料区光电
if (AppFlagKey.PlateBoxLidPPSState.enabled)
virtualWarningState.find(AppFlagKey.PlateBoxLidPPSState).state = true; //入料区光电
}
synchronized public void resetVirtualState() {
initVirtualState();
virtualWarningState = deviceVirtualStateMgrService.getDeviceFlagStateVirtualStateInitVal(deviceWarningFlagState);
}
}
}

104
src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java

@ -68,25 +68,10 @@ public class ConsumablesMgrService {
@PostConstruct
void init() {
// for (var ch : ConsumableGroup.values()) {
// ReactionPlateContainer reactionPlateContainer = appStatePersistenceDao.getReactionPlateContainer(ch);
// if (reactionPlateContainer == null)
// continue;
//
// if (!reactionPlateContainer.isInstall)
// continue;
//
// try {
// installConsumable(ch.off, reactionPlateContainer.projId, reactionPlateContainer.lotId);
// } catch (AppException ignored) {
// }
// }
}
//耗材状态
// private final A8kConsumableContainer cState = new A8kConsumableContainer();
private Integer stateVersion = 0;
@ -185,6 +170,10 @@ public class ConsumablesMgrService {
ReactionPlateContainerInfo reactionPlateContainerInfo,
LittBottleConsumablesInfo littBottleConsumablesInfo,
LargeBottleConsumablesInfo largeBottleConsumablesInfo) {
reactionPlateContainerStateMgr.uninstall(ConsumableGroup.of(ch));
littBottleContainerStateMgr.uninstall(ConsumableGroup.of(ch));
larBottleContainerStateMgr.uninstall(ConsumableGroup.of(ch));
if (reactionPlateContainerInfo != null) {
reactionPlateContainerStateMgr.install(Objects.requireNonNull(ConsumableGroup.of(ch)), reactionPlateContainerInfo);
}
@ -221,44 +210,53 @@ public class ConsumablesMgrService {
LittBottleConsumablesInfo littBottleConsumablesInfo = null;
LargeBottleConsumablesInfo largeBottleConsumablesInfo = null;
if (reactionType.equals(A8kReactionFlowType.SampleAndBS)) {
reactionPlateContainer = new ReactionPlateContainerInfo(
projId,
projExtInfoCard.projName,
projCfg.projShortName,
lotid,
projExtInfoCard.color);
littBottleConsumablesInfo = new LittBottleConsumablesInfo(
LittleBottleConsumableType.BufferSolution,
projId,
projExtInfoCard.projName,
projCfg.projShortName,
lotid,
projExtInfoCard.color);
} else if (reactionType.equals(A8kReactionFlowType.SampleAndBSAndProbeSubstance)) {
reactionPlateContainer = new ReactionPlateContainerInfo(
projId,
projExtInfoCard.projName,
projCfg.projShortName,
lotid,
projExtInfoCard.color);
littBottleConsumablesInfo = new LittBottleConsumablesInfo(
LittleBottleConsumableType.ProbeSubstance,
projId,
projExtInfoCard.projName,
projCfg.projShortName,
lotid,
projExtInfoCard.color);
largeBottleConsumablesInfo = new LargeBottleConsumablesInfo(
projId,
projExtInfoCard.projName,
projCfg.projShortName,
lotid,
projExtInfoCard.color);
} else {
throw new RuntimeException("未知的反应流程类型");
switch (reactionType) {
case SampleAndBS -> {
reactionPlateContainer = new ReactionPlateContainerInfo(
projId,
projExtInfoCard.projName,
projCfg.projShortName,
lotid,
projExtInfoCard.color);
littBottleConsumablesInfo = new LittBottleConsumablesInfo(
LittleBottleConsumableType.BufferSolution,
projId,
projExtInfoCard.projName,
projCfg.projShortName,
lotid,
projExtInfoCard.color);
}
case SampleAndBSAndProbeSubstance -> {
reactionPlateContainer = new ReactionPlateContainerInfo(
projId,
projExtInfoCard.projName,
projCfg.projShortName,
lotid,
projExtInfoCard.color);
littBottleConsumablesInfo = new LittBottleConsumablesInfo(
LittleBottleConsumableType.ProbeSubstance,
projId,
projExtInfoCard.projName,
projCfg.projShortName,
lotid,
projExtInfoCard.color);
largeBottleConsumablesInfo = new LargeBottleConsumablesInfo(
projId,
projExtInfoCard.projName,
projCfg.projShortName,
lotid,
projExtInfoCard.color);
}
case SampleOnly -> {
reactionPlateContainer = new ReactionPlateContainerInfo(
projId,
projExtInfoCard.projName,
projCfg.projShortName,
lotid,
projExtInfoCard.color);
}
}
//更新耗材

47
src/main/java/a8k/app/service/statemgr/DeviceWorkStateMgrService.java

@ -18,6 +18,7 @@ import java.util.List;
public class DeviceWorkStateMgrService {
final private GStateMgrService gstate;
DeviceWorkState deviceWorkState = new DeviceWorkState();
Integer version = 0;
synchronized public DeviceWorkState getDeviceWorkState() {
@ -29,6 +30,9 @@ public class DeviceWorkStateMgrService {
return deviceWorkState;
}
synchronized public Integer getVersion() {
return version;
}
//
// WORK STATE GETTER AND SETTER
@ -36,14 +40,19 @@ public class DeviceWorkStateMgrService {
synchronized public void setStopActionPending(Boolean stopActionPending) {
deviceWorkState.stopActionPending = stopActionPending;
version++;
}
synchronized public void setPauseActionPending(Boolean pauseActionPending) {
deviceWorkState.pauseActionPending = pauseActionPending;
version++;
}
synchronized public void setResumeActionPending(Boolean resumeActionPending) {
deviceWorkState.resumeActionPending = resumeActionPending;
version++;
}
synchronized public void setStartActionPending(A8kWorkTaskType workTaskType, Boolean startActionPending) {
@ -52,17 +61,43 @@ public class DeviceWorkStateMgrService {
deviceWorkState.stopActionPending = false;
deviceWorkState.pauseActionPending = false;
deviceWorkState.resumeActionPending = false;
version++;
}
synchronized public void clearPending() {
deviceWorkState.clearPending();
version++;
}
synchronized public void updateWorkState(A8kWorkState workState) {
deviceWorkState.lastWorkState = deviceWorkState.workState;
deviceWorkState.workState = workState;
version++;
}
synchronized public void setFatalErrorFlag(AppError appError) {
gstate.setFatalError(appError);
deviceWorkState.fatalErrorFlag = true;
version++;
}
synchronized public void clearFatalErrorFlag() {
gstate.clearFatalError();
deviceWorkState.fatalErrorFlag = false;
version++;
}
synchronized public void setMayHaveNewTubeHolder(Boolean val) {
deviceWorkState.mayHaveNewTubeHolder = val;
version++;
}
@ -109,15 +144,6 @@ public class DeviceWorkStateMgrService {
// ERROR FLAG FUNCTIONS
//
synchronized public void setFatalErrorFlag(AppError appError) {
gstate.setFatalError(appError);
deviceWorkState.fatalErrorFlag = true;
}
synchronized public void clearFatalErrorFlag() {
gstate.clearFatalError();
deviceWorkState.fatalErrorFlag = false;
}
//
// SOME FLAGS
@ -126,8 +152,5 @@ public class DeviceWorkStateMgrService {
return deviceWorkState.mayHaveNewTubeHolder;
}
synchronized public void setMayHaveNewTubeHolder(Boolean val) {
deviceWorkState.mayHaveNewTubeHolder = val;
}
}

11
src/main/java/a8k/app/service/statemgr/GStateMgrService.java

@ -1,6 +1,7 @@
package a8k.app.service.statemgr;
import a8k.app.i18n.Internationalization;
import a8k.app.service.DeviceVirtualStateMgrService;
import a8k.app.type.BoardVersions;
import a8k.app.type.DeviceRunMode;
import a8k.app.type.GState;
@ -20,6 +21,7 @@ import org.springframework.stereotype.Component;
@RequiredArgsConstructor
public class GStateMgrService {
private final GState gState;
private final DeviceVirtualStateMgrService deviceVirtualStateMgrService;
public synchronized Boolean isDeviceInited() {
@ -35,16 +37,9 @@ public class GStateMgrService {
}
Integer i = 0;
public synchronized SensorState getSensorState() {
if (isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
SensorState sensorState = new SensorState();
sensorState.setPboxTemperature(-i % 40);
sensorState.setIncubateBoxTemperature(i % 40);
sensorState.setWasteBinFullFlag((i / 100) % 2 == 0);
i++;
return sensorState;
return deviceVirtualStateMgrService.getVirtualSensorState();
}
return this.gState.sensorState;
}

51
src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgr.java

@ -2,6 +2,7 @@ package a8k.app.service.statemgr;
import a8k.app.factory.ZAppPromptFactory;
import a8k.app.channel.iflytophald.type.protocol.A8kEcode;
import a8k.app.service.DeviceVirtualStateMgrService;
import a8k.app.type.DeviceRunMode;
import a8k.app.type.a8k.BloodType;
import a8k.app.type.a8k.pos.ConsumableInfo;
@ -18,6 +19,7 @@ import a8k.app.service.utils.ProjInfoUtils;
import a8k.app.utils.ZTimeUtils;
import cn.hutool.core.util.ObjectUtil;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@ -28,6 +30,7 @@ import java.util.List;
@Component
@Slf4j
@RequiredArgsConstructor
public class IncubationPlateStateMgr {
@FunctionalInterface
@ -35,61 +38,19 @@ public class IncubationPlateStateMgr {
void syncState(IncubatorPos pos);
}
@Resource
GStateMgrService gStateMgrService;
private final GStateMgrService gStateMgrService;
private final DeviceVirtualStateMgrService deviceVirtualStateMgrService;
//孵育盘状态
private final IncubationPlate incubationPlate = new IncubationPlate();
synchronized public IncubationPlate get() {
if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
return getVirtualState();
return deviceVirtualStateMgrService.getVirtualIncubationPlateState();
}
return ObjectUtil.cloneByStream(incubationPlate);
}
synchronized public IncubationPlate getVirtualState() {
IncubationPlate incubationPlate = new IncubationPlate();
int i = 0;
for (IncubationSubTank subtank : incubationPlate.subtanks) {
i++;
switch (i % 6) {
case 0 -> subtank.state = IncubationSubTankState.EMPTY;
case 1 -> subtank.state = IncubationSubTankState.RESERVED;
case 2 -> subtank.state = IncubationSubTankState.INCUBATING;
case 3 -> subtank.state = IncubationSubTankState.INCUBATION_COMPLETE;
case 4 -> subtank.state = IncubationSubTankState.ERROR;
case 5 -> subtank.state = IncubationSubTankState.WAITING_FOR_DROP;
}
subtank.sampleInfo = new SampleInfo(
"250109_001E01", 0, false, false, BloodType.WHOLE_BLOOD, "112334455667", "250109_001E"
);
subtank.sampleInfo.bloodType = BloodType.WHOLE_BLOOD;
subtank.sampleInfo.sampleBarcode = "112334455667";
subtank.sampleInfo.userid = "250109_001E";
subtank.projInfo = new ProjBriefInfo();
subtank.projInfo.projId = 1;
subtank.projInfo.projName = "hsCRP";
subtank.projInfo.projShortName = "CA";
subtank.projInfo.color = "#DC143C";
subtank.sampleInfo.sampleId = "250109_001E01";
subtank.projId = 1;
subtank.lotId = "CA123456";
subtank.isEmergency = i % 2 == 0;
if (subtank.state.equals(IncubationSubTankState.ERROR)) {
subtank.error = new AppError(A8kEcode.PROJ_CARD_ERROR_WRONG_UNSUPPORTED, "");
subtank.errorInfo = ZAppPromptFactory.buildAppPrompt(subtank.error);
}
subtank.startIncubatedTime = new Date().getTime();
subtank.incubatedTimeSec = 3 * 60;
subtank.remainTimeSec = 3 * 60;
}
return incubationPlate;
}
synchronized public IncubationSubTank getSubTank(IncubatorPos pos) {
return incubationPlate.subtanks[pos.off];
}

14
src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java

@ -22,6 +22,9 @@ public class OptScanModuleStateMgr {
@Resource
GStateMgrService gStateMgrService;
Integer version = 0;
//光学模组状态
private final OptScanModuleState optScanModule = new OptScanModuleState();
@ -39,6 +42,7 @@ public class OptScanModuleStateMgr {
synchronized public void setCleared(Boolean cleared) {
optScanModule.setCleared(cleared);
version++;
}
synchronized public IncubationRecordInfo getIncubationRecordInfo() {
@ -60,12 +64,20 @@ public class OptScanModuleStateMgr {
return ObjectUtil.cloneByStream(optScanModule);
}
synchronized public Integer getStateVersion() {
if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
return 1;
}
return version;
}
synchronized public void changeOptScanModuleStateToEmpty() {
optScanModule.state = OptScanModuleStateEnum.EMPTY;
optScanModule.sampleInfo = SampleInfo.createEmpty();
optScanModule.setProjInfo(null);
optScanModule.setProjId(null);
log.info("光学模块: 状态->空闲");
version++;
}
synchronized public void changeOptScanModuleStateToPlateIsReady(String cxtid, SampleInfo sampleInfo, IncubationRecordInfo incubationRecordInfo, ProjBuildInInfo projBuildinInfo,
@ -80,12 +92,14 @@ public class OptScanModuleStateMgr {
optScanModule.setCxtId(cxtid);
optScanModule.setIncubationRecordInfo(incubationRecordInfo);
log.info("光学模块:状态->反应板准备就绪 {}", sampleInfo);
version++;
}
synchronized public void changeOptScanModuleStateToScanning() {
log.info("光学模块: 状态->开始扫描");
optScanModule.state = OptScanModuleStateEnum.SCANNING;
version++;
}

52
src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java

@ -2,6 +2,7 @@ package a8k.app.service.statemgr;
import a8k.app.constant.AppConstant;
import a8k.app.factory.FakeA8kConsumableContainerFactory;
import a8k.app.service.DeviceVirtualStateMgrService;
import a8k.app.service.data.ProjInfoMgrService;
import a8k.app.service.utils.ProjInfoUtils;
import a8k.app.type.DeviceRunMode;
@ -32,6 +33,7 @@ public class PreReactionStateMgr {
private final ProjInfoMgrService projInfoMgrService;
private final GStateMgrService gStateMgrService;
private final DeviceVirtualStateMgrService deviceVirtualStateMgrService;
PreReactionPosState preReactionPosState = new PreReactionPosState();
@ -39,57 +41,11 @@ public class PreReactionStateMgr {
return ObjectUtil.cloneByStream(preReactionPosState);
}
private PreReactionGridGroup buildFakePreReactionGridGroup(ConsumableGroup group) {
PreReactionGridGroup gridGroup = new PreReactionGridGroup(group);
gridGroup.group = group;
if (group.off % 2 == 0) {
gridGroup.installed = true;
gridGroup.hasSomeGridInReacting = true;
gridGroup.hasSomeGridReactedCompleted = true;
} else {
gridGroup.installed = false;
gridGroup.hasSomeGridInReacting = false;
gridGroup.hasSomeGridReactedCompleted = false;
}
gridGroup.consumableType = LittleBottleConsumableType.BufferSolution;
var projBuildInInfo = FakeA8kConsumableContainerFactory.buildFakeProjBuildInInfo(group.off);
gridGroup.projBriefInfo = ProjInfoUtils.buildProjBrefInfo(projBuildInInfo);
gridGroup.version = 10;
for (int i = 0; i < AppConstant.CONSUMABLE_NUM; i++) {
gridGroup.grids.get(i).projId = projBuildInInfo.projId;
gridGroup.grids.get(i).projBuildinInfo = projBuildInInfo;
gridGroup.grids.get(i).projExtInfoCard = null;
switch (i / 5) {
case 0 -> {
gridGroup.grids.get(i).state = PreReactionGrid.State.UNINSTALL;
}
case 1 -> {
gridGroup.grids.get(i).state = PreReactionGrid.State.USED;
}
case 2 -> {
gridGroup.grids.get(i).state = PreReactionGrid.State.REACTION_COMPLETED;
gridGroup.grids.get(i).sampleInfo.userid = "FAKE-UID-123";
}
case 3 -> {
gridGroup.grids.get(i).state = PreReactionGrid.State.REACTING;
gridGroup.grids.get(i).sampleInfo.userid = "FAKE-UID-121";
gridGroup.grids.get(i).reactionRemainingTime = i * 60L;
}
case 4 -> {
gridGroup.grids.get(i).state = PreReactionGrid.State.TO_BE_USED;
}
}
}
return gridGroup;
}
public synchronized PreReactionGridGroup getPreReactionGridGroupState(ConsumableGroup group) {
if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
return buildFakePreReactionGridGroup(group);
return deviceVirtualStateMgrService.getFakePreReactionGridGroup(group);
}
PreReactionGridGroup gridGroup = getPreReactionGridGroup(group);
return ObjectUtil.cloneByStream(gridGroup);
@ -106,7 +62,7 @@ public class PreReactionStateMgr {
public synchronized Integer getPreReactionGridGroupVersion(ConsumableGroup group) {
if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
return buildFakePreReactionGridGroup(group).version;
return deviceVirtualStateMgrService.getFakePreReactionGridGroup(group).version;
}
PreReactionGridGroup gridGroup = getPreReactionGridGroup(group);

208
src/main/java/a8k/app/service/statemgr/TubeStateMgr.java

@ -1,9 +1,8 @@
package a8k.app.service.statemgr;
import a8k.app.dao.type.db.DeviceStatistic;
import a8k.app.factory.FakeA8kConsumableContainerFactory;
import a8k.app.factory.FakeAppErrorFactory;
import a8k.app.factory.ZAppPromptFactory;
import a8k.app.service.DeviceVirtualStateMgrService;
import a8k.app.service.analyzer.ConsumableStateAnalyzerService;
import a8k.app.type.DeviceRunMode;
import a8k.app.type.a8k.pos.ConsumableInfo;
@ -26,7 +25,6 @@ import a8k.app.dao.type.combination.ProjBuildInInfo;
import a8k.app.service.utils.ProjInfoUtils;
import a8k.app.service.utils.ZAppChecker;
import a8k.app.utils.ZJsonHelper;
import a8k.app.utils.ZList;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -48,6 +46,7 @@ public class TubeStateMgr {
private final ProjInfoMgrService projInfoMgrService;
private final ConsumablesMgrService consumablesMgrService;
private final ConsumableStateAnalyzerService consumableStateAnalyzerService;
private final DeviceVirtualStateMgrService deviceVirtualStateMgrService;
private final SampleRecordDBDao sampleRecordDBDao;
@ -58,58 +57,34 @@ public class TubeStateMgr {
private final TubeHolder tubeHolder = new TubeHolder(); //当前正在被处理的试管架状态
private final EmergencyTubePos emergencyTubePos = new EmergencyTubePos(); //急诊为状态
private Tube curProcessingTube;
private Integer version = 0;
private String priGenerateSampleId(Integer tubePos, Boolean isEmergency) {
String sampleid = "";
Integer cnt = 0;
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
if (isEmergency) {
cnt = deviceStatisticDao.get(DeviceStatistic.StatisticType.EmergencyTubeCnt, date);
sampleid = String.format("%s_%sE", sdf.format(date), cnt);
deviceStatisticDao.setCnt(DeviceStatistic.StatisticType.EmergencyTubeCnt, date, cnt + 1);
} else {
cnt = deviceStatisticDao.get(DeviceStatistic.StatisticType.TubeHolderCnt, date);
sampleid = String.format("%s_%d%02d", sdf.format(date), cnt, tubePos + 1);
deviceStatisticDao.setCnt(DeviceStatistic.StatisticType.TubeHolderCnt, date, cnt + 1);
synchronized public EmergencyTubePos getEmergencyPosRunState() {
if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
return deviceVirtualStateMgrService.getVirtualEmergencyTube();
}
return sampleid;
return ObjectUtil.cloneByStream(emergencyTubePos);
}
private void assignSampleRecord(Tube tube, SampleRecord sampleRecord) {
sampleRecord.bloodType = tube.getBloodType();
sampleRecord.isEmergency = tube.getIsEmergency();
sampleRecord.sampleBarcode = tube.getSampleBarcode();
if (tube.getUserid() == null || tube.getUserid().isEmpty()) {
sampleRecord.userid = sampleRecord.sampleid;
} else {
sampleRecord.userid = tube.getUserid();
public synchronized TubeHolder getTubeHolderState() {
if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
return deviceVirtualStateMgrService.getVirtualTubeHolderState();
}
sampleRecord.projIds = tube.getProjIds();
return ObjectUtil.cloneByStream(tubeHolder);
}
private void updateSampleInfo(Tube tube) {
SampleRecord sampleRecord = sampleRecordDBDao.findBySampleId(tube.getSampleId());
if (sampleRecord == null) {
return;
}
assignSampleRecord(tube, sampleRecord);
sampleRecordDBDao.update(sampleRecord);
public synchronized Integer getVersion() {
return version;
}
private void deleteSampleInfo(String sampleId) {
sampleRecordDBDao.deleteBySampleId(sampleId);
}
/**
* 向样本数据库中插入一个新的样本信息,并返回唯一的样本ID
* @param tube 试管
* @return 样本ID
*/
public String newSample(Tube tube) {
private String newSample(Tube tube) {
SampleRecord sampleRecord = new SampleRecord();
sampleRecord.sampleid = priGenerateSampleId(tube.getPos(), tube.getIsEmergency());
sampleRecord.createDate = new Date();
@ -131,18 +106,6 @@ public class TubeStateMgr {
return new ProjectPreProcessContext(sampleInfo, consumableInfo, projId, projBuildinInfo, projExtInfoCard, off);
}
public synchronized void initTubeByTubeInfo(Tube tube, TubeInfo tubeInfo) {
if (!tubeInfo.isHasTube) {
tube.reset();
return;
}
if (tubeInfo.projIds.isEmpty()) {
tube.reset();
return;
}
}
//
//试管状态管理
@ -209,7 +172,7 @@ public class TubeStateMgr {
tubeHolder.reset();
throw e;
}
version++;
}
@ -288,6 +251,8 @@ public class TubeStateMgr {
}
throw e;
}
version++;
}
synchronized public void setTubeCxtIncubationPos(ProjectPreProcessContext cxt, IncubatorPos pos) {
@ -296,6 +261,9 @@ public class TubeStateMgr {
return;
}
version++;
if (emergencyTubePos.tube != null) {
for (ProjectPreProcessContext context : emergencyTubePos.tube.getPreProcessContexts()) {
if (context.getCxtId().equals(cxt.getCxtId())) {
@ -341,83 +309,6 @@ public class TubeStateMgr {
return ObjectUtil.cloneByStream(tubeHolder.getTubes()[pos]);
}
static Tube createFakeTube(Integer pos) {
Tube tube = new Tube(pos);
tube.setSampleId("250109_001E0" + pos);
tube.setBloodType(BloodType.WHOLE_BLOOD);
tube.setSampleBarcode("112334455667");
tube.setUserid(String.format("250109_%dE", pos));
var toBeUsedPBI = ZList.of(
FakeA8kConsumableContainerFactory.buildFakeProjBriefInfo(0),
FakeA8kConsumableContainerFactory.buildFakeProjBriefInfo(1),
FakeA8kConsumableContainerFactory.buildFakeProjBriefInfo(2),
FakeA8kConsumableContainerFactory.buildFakeProjBriefInfo(3),
FakeA8kConsumableContainerFactory.buildFakeProjBriefInfo(4),
FakeA8kConsumableContainerFactory.buildFakeProjBriefInfo(5)
);
for (int i = 0; i < pos; i++) {
if (i >= 6)
break;
if (i < toBeUsedPBI.size()) {
tube.getProjInfo().add(toBeUsedPBI.get(i));
tube.getProjIds().add(toBeUsedPBI.get(i).projId);
}
}
switch (pos) {
case 0 -> tube.setState(TubeState.TO_BE_PROCESSED);
case 1 -> tube.setState(TubeState.PENDING);
case 2 -> tube.setState(TubeState.RESOURCE_IS_READY);
case 3 -> tube.setState(TubeState.PROCESSING);
case 4, 5, 7, 8 -> tube.setState(TubeState.PROCESS_COMPLETE);
case 6 -> {
tube.setState(TubeState.ERROR);
tube.setError(FakeAppErrorFactory.buildAEConsumeNotEnoughError());
tube.setErrorInfo(ZAppPromptFactory.buildAppPrompt(tube.getError()));
}
case 9 -> tube.setState(TubeState.EMPTY);
}
tube.setIsHighTube(pos % 2 == 0); //假设偶数位置为高位管
return tube;
}
synchronized public EmergencyTubePos getEmergencyPosRunState() {
if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
var tubePosState = new EmergencyTubePos();
tubePosState.tube = createFakeTube(3);
tubePosState.tube.setPos(0);
tubePosState.tube.setIsEmergency(true);
return tubePosState;
}
return ObjectUtil.cloneByStream(emergencyTubePos);
}
public synchronized TubeHolder getTubeHolder() {
if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
TubeHolder tubeHolder = new TubeHolder();
tubeHolder.setTubes(new Tube[]{
createFakeTube(0),
createFakeTube(1),
createFakeTube(2),
createFakeTube(3),
createFakeTube(4),
createFakeTube(5),
createFakeTube(6),
createFakeTube(7),
createFakeTube(8),
createFakeTube(9)
});
tubeHolder.setState(TubeHolderState.PROCESSING);
return tubeHolder;
}
return ObjectUtil.cloneByStream(tubeHolder);
}
//
// STATE CHANGE HELPER
@ -431,17 +322,23 @@ public class TubeStateMgr {
log.info("挂起一个待处理试管 SampleId:{} \n{}", curProcessingTube.getSampleId(), ZJsonHelper.objectToJson(curProcessingTube));
curProcessingTube.setState(TubeState.PENDING);
version++;
}
synchronized public void changeTubeStateToResourceIsReady() {
log.info("试管 状态->资源准备就绪 SampleId:{}", curProcessingTube.getSampleId());
curProcessingTube.setState(TubeState.RESOURCE_IS_READY);
version++;
}
synchronized public void changeTubeStateToProcessing() {
log.info("试管 状态->处理中 SampleId:{}", curProcessingTube.getSampleId());
curProcessingTube.setState(TubeState.PROCESSING);
version++;
}
@ -451,17 +348,23 @@ public class TubeStateMgr {
curProcessingTube.setError(error);
curProcessingTube.setErrorInfo(ZAppPromptFactory.buildAppPrompt(error));
curProcessingTube = null;
version++;
}
synchronized public void changeTubeStateToProcessComplete() {
log.info("试管 状态->处理完成 SampleId:{}", curProcessingTube.getSampleId());
curProcessingTube.setState(TubeState.PROCESS_COMPLETE);
curProcessingTube = null;
version++;
}
synchronized public void changeTubeHolderStateToIDLE() {
log.info("试管架 状态->空闲");
tubeHolder.reset();
version++;
}
synchronized public void resetAll() {
@ -469,6 +372,8 @@ public class TubeStateMgr {
curProcessingTube = null;
tubeHolder.reset();
emergencyTubePos.tube.setState(TubeState.EMPTY);
version++;
}
@ -486,6 +391,7 @@ public class TubeStateMgr {
}
}
//没有下一个试管
version++;
return nextTubeIndex;
}
@ -529,4 +435,48 @@ public class TubeStateMgr {
}
private String priGenerateSampleId(Integer tubePos, Boolean isEmergency) {
String sampleid = "";
Integer cnt = 0;
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
if (isEmergency) {
cnt = deviceStatisticDao.get(DeviceStatistic.StatisticType.EmergencyTubeCnt, date);
sampleid = String.format("%s_%sE", sdf.format(date), cnt);
deviceStatisticDao.setCnt(DeviceStatistic.StatisticType.EmergencyTubeCnt, date, cnt + 1);
} else {
cnt = deviceStatisticDao.get(DeviceStatistic.StatisticType.TubeHolderCnt, date);
sampleid = String.format("%s_%d%02d", sdf.format(date), cnt, tubePos);
deviceStatisticDao.setCnt(DeviceStatistic.StatisticType.TubeHolderCnt, date, cnt + 1);
}
return sampleid;
}
private void assignSampleRecord(Tube tube, SampleRecord sampleRecord) {
sampleRecord.bloodType = tube.getBloodType();
sampleRecord.isEmergency = tube.getIsEmergency();
sampleRecord.sampleBarcode = tube.getSampleBarcode();
if (tube.getUserid() == null || tube.getUserid().isEmpty()) {
sampleRecord.userid = sampleRecord.sampleid;
} else {
sampleRecord.userid = tube.getUserid();
}
sampleRecord.projIds = tube.getProjIds();
}
private void updateSampleInfo(Tube tube) {
SampleRecord sampleRecord = sampleRecordDBDao.findBySampleId(tube.getSampleId());
if (sampleRecord == null) {
return;
}
assignSampleRecord(tube, sampleRecord);
sampleRecordDBDao.update(sampleRecord);
}
private void deleteSampleInfo(String sampleId) {
sampleRecordDBDao.deleteBySampleId(sampleId);
}
}

40
src/main/java/a8k/app/type/DeviceWarningFlagStateGroup.java

@ -0,0 +1,40 @@
package a8k.app.type;
import a8k.app.service.statemgr.AppFlagStateMgr;
import java.util.ArrayList;
import java.util.List;
public class DeviceWarningFlagStateGroup implements java.io.Serializable {
public List<AppFlagStateMgr.AppFlagState> states = new ArrayList<>();
public Integer version = 0; //状态版本号
// 别删,被前端使用
public Boolean isHasWarningTriggerFlag() {
for (AppFlagStateMgr.AppFlagState state : states) {
if (state.flagType.equals(AppFlagType.WarningFlag) && state.state) {
return true; //如果有任意一个状态为true,则返回true
}
}
return false; //如果没有任意一个状态为true,则返回false
}
public Boolean isHasErrorTriggerFlag() {
for (AppFlagStateMgr.AppFlagState state : states) {
if (state.flagType.equals(AppFlagType.ErrorFlag) && state.state) {
return true; //如果有任意一个状态为true,则返回true
}
}
return false; //如果没有任意一个状态为true,则返回false
}
public AppFlagStateMgr.AppFlagState find(AppFlagKey appFlagKey) {
for (AppFlagStateMgr.AppFlagState state : states) {
if (state.keyName.equals(appFlagKey)) {
return state;
}
}
// AppFlagStateMgr.log.error("find: Unknown DeviceWarningFlagState: {}", appFlagKey.name());
return null; //如果没有找到,返回null
}
}

4
src/main/java/a8k/app/type/GState.java

@ -24,9 +24,9 @@ public class GState {
public String mcuVersion = "";
public BoardVersions mcuVersionDetail = new BoardVersions(); //MCU版本详细信息
//设备SN
public String sn = "TEST001";//
public String sn = "TEST001";// 巴迪泰 叫做 工厂序列号(FactorySerial)
//
public String assetId = "TEST001";// 资产ID
public String assetId = "TEST001";// 巴迪泰 叫做 出厂序列号(DeviceSerial)
//
public Boolean fatalError = false;
//

2
src/main/java/a8k/app/type/a8k/state/Tube.java

@ -20,7 +20,7 @@ public class Tube implements Serializable {
@Schema(description = "样本ID,系统生成-唯一标识一个样本")
String sampleId; //样本ID-系统生成-唯一标识一个样本
@Schema(description = "样本在样本架上的位置")
Integer pos = -1; //样本在样本架上的位置
Integer pos = -1; //样本在样本架上的位置 1->10
@Schema(description = "是否高位管")
Boolean isHighTube = false;

4
src/main/java/a8k/app/type/a8k/state/TubeHolder.java

@ -18,13 +18,11 @@ public class TubeHolder implements Serializable {
public TubeHolder() {
for (int i = 0; i < tubes.length; i++) {
tubes[i] = new Tube(i);
tubes[i] = new Tube(i + 1);
}
}
public void reset() {
this.state = TubeHolderState.IDLE;
for (Tube tube : tubes) {

12
src/main/java/a8k/app/type/appevent/AppLoginEvent.java

@ -0,0 +1,12 @@
package a8k.app.type.appevent;
import a8k.app.dao.type.db.AppUser;
public class AppLoginEvent extends AppEvent {
public AppUser user;
public AppLoginEvent(AppUser user) {
super(AppLoginEvent.class.getSimpleName());
this.user = user;
}
}

2
src/main/java/a8k/app/type/lisprotocol/BiLisDoubleTrackFrame.java

@ -8,7 +8,7 @@ public class BiLisDoubleTrackFrame {
public static final Integer PACKET_MAX_LENGTH = 1024; // 最大包长度
public static final byte STX = 0x02; // Start of Text
public static final byte FN = 0x01; // Start of Text
public static final char FN = '1'; // Start of Text
public static final byte ETB = 0x17; // End of Text Block
public static final byte CR = 0x0D; // Carriage Return
public static final byte LF = 0x0A; // Line Feed

10
src/main/java/a8k/app/type/lisprotocol/BiLisDoubleTrackFrameBuildContext.java

@ -0,0 +1,10 @@
package a8k.app.type.lisprotocol;
public class BiLisDoubleTrackFrameBuildContext {
public BiLisDoubleTrackFrame frame;
public byte[] frameBytes;
public String frameContentStr;
public char[] checksum;
public Boolean buildSuccess = true;
}

22
src/main/java/a8k/extui/page/debug/P12TueStateDebugPage.java

@ -18,57 +18,57 @@ public class P12TueStateDebugPage {
@ExtApiStatu(name = "", group = "试管架状态", minWidth = "100%", order = 1)
public TubeHolder getTubeHolder() {
return tubeStateMgrService.getTubeHolder();
return tubeStateMgrService.getTubeHolderState();
}
@ExtApiStatu(name = "", group = "试管1", order = 2)
public Tube getTube0State() {
return tubeStateMgrService.getTubeHolder().getTubes()[0];
return tubeStateMgrService.getTubeHolderState().getTubes()[0];
}
@ExtApiStatu(name = "", group = "试管2", order = 3)
public Tube getTube1State() {
return tubeStateMgrService.getTubeHolder().getTubes()[1];
return tubeStateMgrService.getTubeHolderState().getTubes()[1];
}
@ExtApiStatu(name = "", group = "试管3", order = 4)
public Tube getTube2State() {
return tubeStateMgrService.getTubeHolder().getTubes()[2];
return tubeStateMgrService.getTubeHolderState().getTubes()[2];
}
@ExtApiStatu(name = "", group = "试管4", order = 5)
public Tube getTube3State() {
return tubeStateMgrService.getTubeHolder().getTubes()[3];
return tubeStateMgrService.getTubeHolderState().getTubes()[3];
}
@ExtApiStatu(name = "", group = "试管5", order = 6)
public Tube getTube4State() {
return tubeStateMgrService.getTubeHolder().getTubes()[4];
return tubeStateMgrService.getTubeHolderState().getTubes()[4];
}
@ExtApiStatu(name = "", group = "试管6", order = 7)
public Tube getTube5State() {
return tubeStateMgrService.getTubeHolder().getTubes()[5];
return tubeStateMgrService.getTubeHolderState().getTubes()[5];
}
@ExtApiStatu(name = "", group = "试管7", order = 8)
public Tube getTube6State() {
return tubeStateMgrService.getTubeHolder().getTubes()[6];
return tubeStateMgrService.getTubeHolderState().getTubes()[6];
}
@ExtApiStatu(name = "", group = "试管8", order = 9)
public Tube getTube7State() {
return tubeStateMgrService.getTubeHolder().getTubes()[7];
return tubeStateMgrService.getTubeHolderState().getTubes()[7];
}
@ExtApiStatu(name = "", group = "试管9", order = 10)
public Tube getTube8State() {
return tubeStateMgrService.getTubeHolder().getTubes()[8];
return tubeStateMgrService.getTubeHolderState().getTubes()[8];
}
@ExtApiStatu(name = "", group = "试管10", order = 11)
public Tube getTube9State() {
return tubeStateMgrService.getTubeHolder().getTubes()[9];
return tubeStateMgrService.getTubeHolderState().getTubes()[9];
}

88
src/test/java/a8k/app/factory/BiLisDoubleTrackFrameFactoryTest.java

@ -0,0 +1,88 @@
package a8k.app.factory;
import a8k.app.constant.AppConstant;
import a8k.app.type.lisprotocol.BiLisDoubleTrackFrameBuildContext;
import a8k.app.utils.ByteArrayUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@Slf4j
class BiLisDoubleTrackFrameFactoryTest {
@Test
void createRFrame() {
}
@Test
void createRFrameBytes() {
}
@Test
void createOFrame() {
}
@Test
void createQFrameBytes() {
BiLisDoubleTrackFrameBuildContext cxt = BiLisDoubleTrackFrameFactory.createQFrameBytes("A8000", "123456789");
log.info("frameBytes {}", ByteArrayUtils.toByteString(cxt.frameBytes));
log.info("frameContent {}",cxt.frameContentStr);
log.info("checksum {} {}", cxt.checksum[0], cxt.checksum[1]);
assertNotNull(cxt);
assertTrue(cxt.buildSuccess);
assertEquals("Q|A8000|^123456789|\r", cxt.frameContentStr);
}
@Test
void serialize() {
}
@Test
void createBiLisDoubleTrackFrame() {
}
@Test
void serializeFrameContent() {
}
@Test
void removeTrailingPipes() {
String str = "O|A5000p|1111||^NT-proBNP^^|||20220401112632\r";
String result = BiLisDoubleTrackFrameFactory.removeTrailingPipes(str);
assertEquals("O|A5000p|1111||^NT-proBNP^^|||20220401112632\r", result);
str = "O|A5000p|1111||^NT-proBNP^^|||20220401112632||||\r";
result = BiLisDoubleTrackFrameFactory.removeTrailingPipes(str);
assertEquals("O|A5000p|1111||^NT-proBNP^^|||20220401112632|\r", result);
}
@Test
void computeChecksum() {
char[] checksum = BiLisDoubleTrackFrameFactory.computeChecksum("O|A5000p|1111||^NT-proBNP^^|||20220401112632\r");
assertEquals(2, checksum.length);
assertEquals('0', checksum[0]);
assertEquals('2', checksum[1]);
}
@Test
void intToHexChars() {
char[] chars;
chars = BiLisDoubleTrackFrameFactory.intToHexChars(0x23);
assertEquals(2, chars.length);
assertEquals('2', chars[0]);
assertEquals('3', chars[1]);
chars = BiLisDoubleTrackFrameFactory.intToHexChars(0x0A);
assertEquals(2, chars.length);
assertEquals('0', chars[0]);
assertEquals('a', chars[1]);
}
@Test
void strArraySafeGet() {
}
}

34
代码说明/20240718.txt

@ -1,34 +0,0 @@
```
1.添加下面几种数据类型,每种类型都对应一种json,json的格式已经在对应的类中给出
Pos3d("Pos3d"),//
Pos2d("Pos2d"),//
Bool("Bool"),//
Int("Int"),//
String("String"),//
LargeBottleBufferPosInfo("LargeBottleBufferPosInfo"),//
Plates2dCodeScanPosInfo("Plates2dCodeScanPosInfo"),//
SmallBottleBufferPosInfo("SmallBottleBufferPosInfo"),//
TipPickUpPosInfo("TipPickUpPosInfo"),//
TubeSamplePos("TubeSamplePos"),//
Float("Float");
2.Hbot控制涉及到参数的访问和更改写在,HbotControlParamsService
3.反应板夹搬运(板夹出仓,转盘转动...,勾取反应板)相关参数的访问和更改写在 ReactionPlatesTransmitCtrlParamService
4.样本预处理(脱毛盖帽摇匀)涉及到参数的访问和更改写在 SamplesPreProcessModuleCtrlParamsService
5.所有硬件控制涉及到的参数都写在HardwareServiceSetting数据库中,数据库中的条目索引,由key+ServiceName作为索引标识。
6.之前写的进出料控制,也改成类似的风格。(这个我没有改)
7.删除掉试管类型数据库,试管类型信息存储在A8kTubeType枚举中。试管架间距,参数也放在MotorTubeRackMoveCtrlServiceParameterDao中,(我没有删,你改完之后再删)
```
```
1. 添加AppWarningNotifyEvent,前端接收到该事件,弹窗显示dispalyInfo即可
2. 添加AppStepNotifyEvent,前端收到该事件,在页面的信息栏显示dispalyInfo即可。
```
```
regIndex 换成枚举类型
A8kCanBusService添加,read_reg,get_reg 方法
```
Loading…
Cancel
Save