From d82da14e2dee8233b3f8eb8fb6755829aa42cdea Mon Sep 17 00:00:00 2001 From: zhaohe Date: Sun, 13 Jul 2025 11:29:27 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=8A=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 11 +- src/main/java/a8k/OS.java | 2 +- .../v1/app/state/AppFlagStateMgrController.java | 3 +- .../api/v1/app/state/DeviceStateController.java | 2 +- .../api/v1/app/ws/AppWebSocketEndpointMgr.java | 97 ++++---- .../app/factory/BiLisDoubleTrackFrameFactory.java | 78 ++++--- .../app/interceptor/RefreshAccessInterceptor.java | 1 - .../app/service/DeviceVirtualStateMgrService.java | 258 +++++++++++++++++++++ .../a8k/app/service/data/AppUserMgrService.java | 48 +--- .../state/EngineerModeStateMgrService.java | 7 + .../service/mainctrl/AppDeviceInitCtrlService.java | 4 + .../app/service/module/SamplePreProcessModule.java | 4 +- .../app/service/setting/AppSettingsMgrService.java | 2 - .../a8k/app/service/statemgr/AppFlagStateMgr.java | 94 +------- .../service/statemgr/ConsumablesMgrService.java | 104 ++++----- .../statemgr/DeviceWorkStateMgrService.java | 47 +++- .../a8k/app/service/statemgr/GStateMgrService.java | 11 +- .../service/statemgr/IncubationPlateStateMgr.java | 51 +--- .../service/statemgr/OptScanModuleStateMgr.java | 14 ++ .../app/service/statemgr/PreReactionStateMgr.java | 52 +---- .../a8k/app/service/statemgr/TubeStateMgr.java | 208 +++++++---------- .../a8k/app/type/DeviceWarningFlagStateGroup.java | 40 ++++ src/main/java/a8k/app/type/GState.java | 4 +- src/main/java/a8k/app/type/a8k/state/Tube.java | 2 +- .../java/a8k/app/type/a8k/state/TubeHolder.java | 4 +- .../java/a8k/app/type/appevent/AppLoginEvent.java | 12 + .../type/lisprotocol/BiLisDoubleTrackFrame.java | 2 +- .../BiLisDoubleTrackFrameBuildContext.java | 10 + .../a8k/extui/page/debug/P12TueStateDebugPage.java | 22 +- .../factory/BiLisDoubleTrackFrameFactoryTest.java | 88 +++++++ 代码说明/20240718.txt | 34 --- 31 files changed, 763 insertions(+), 553 deletions(-) create mode 100644 src/main/java/a8k/app/service/DeviceVirtualStateMgrService.java create mode 100644 src/main/java/a8k/app/type/DeviceWarningFlagStateGroup.java create mode 100644 src/main/java/a8k/app/type/appevent/AppLoginEvent.java create mode 100644 src/main/java/a8k/app/type/lisprotocol/BiLisDoubleTrackFrameBuildContext.java create mode 100644 src/test/java/a8k/app/factory/BiLisDoubleTrackFrameFactoryTest.java delete mode 100644 代码说明/20240718.txt diff --git a/pom.xml b/pom.xml index 560817f..93283cb 100644 --- a/pom.xml +++ b/pom.xml @@ -127,7 +127,16 @@ jackson-dataformat-yaml 2.12.4 - + + org.springframework.boot + spring-boot-starter-test + test + + + org.mockito + mockito-core + 3.12.4 + diff --git a/src/main/java/a8k/OS.java b/src/main/java/a8k/OS.java index 2e697c0..5624af6 100644 --- a/src/main/java/a8k/OS.java +++ b/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; diff --git a/src/main/java/a8k/app/controler/api/v1/app/state/AppFlagStateMgrController.java b/src/main/java/a8k/app/controler/api/v1/app/state/AppFlagStateMgrController.java index 6927d8e..7f8d674 100644 --- a/src/main/java/a8k/app/controler/api/v1/app/state/AppFlagStateMgrController.java +++ b/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 getFlagState() { + public ApiRet getFlagState() { return ApiRet.success(appFlagStateMgr.getFlagState()); } diff --git a/src/main/java/a8k/app/controler/api/v1/app/state/DeviceStateController.java b/src/main/java/a8k/app/controler/api/v1/app/state/DeviceStateController.java index c927833..19b4cd0 100644 --- a/src/main/java/a8k/app/controler/api/v1/app/state/DeviceStateController.java +++ b/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 getTubeHolderState() { - return ApiRet.success(tubeStateMgrService.getTubeHolder()); + return ApiRet.success(tubeStateMgrService.getTubeHolderState()); } @Operation(summary = "获取<孵育盘>的状态") diff --git a/src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java b/src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java index a7cd557..1ad6f60 100644 --- a/src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java +++ b/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 stateWebsocketSessions = new ArrayList<>(); List eventWebsocketSessions = new ArrayList<>(); - Thread workThread; - Boolean newStateSession = false; Map 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); } } diff --git a/src/main/java/a8k/app/factory/BiLisDoubleTrackFrameFactory.java b/src/main/java/a8k/app/factory/BiLisDoubleTrackFrameFactory.java index a89621e..1c4f93a 100644 --- a/src/main/java/a8k/app/factory/BiLisDoubleTrackFrameFactory.java +++ b/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| + 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 ""; } diff --git a/src/main/java/a8k/app/interceptor/RefreshAccessInterceptor.java b/src/main/java/a8k/app/interceptor/RefreshAccessInterceptor.java index 9843872..0ff77b9 100644 --- a/src/main/java/a8k/app/interceptor/RefreshAccessInterceptor.java +++ b/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; } } diff --git a/src/main/java/a8k/app/service/DeviceVirtualStateMgrService.java b/src/main/java/a8k/app/service/DeviceVirtualStateMgrService.java new file mode 100644 index 0000000..92cdf86 --- /dev/null +++ b/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; + + } +} diff --git a/src/main/java/a8k/app/service/data/AppUserMgrService.java b/src/main/java/a8k/app/service/data/AppUserMgrService.java index 49d08be..480b2fb 100644 --- a/src/main/java/a8k/app/service/data/AppUserMgrService.java +++ b/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; diff --git a/src/main/java/a8k/app/service/engineer/state/EngineerModeStateMgrService.java b/src/main/java/a8k/app/service/engineer/state/EngineerModeStateMgrService.java index 7101070..28d1158 100644 --- a/src/main/java/a8k/app/service/engineer/state/EngineerModeStateMgrService.java +++ b/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++; } diff --git a/src/main/java/a8k/app/service/mainctrl/AppDeviceInitCtrlService.java b/src/main/java/a8k/app/service/mainctrl/AppDeviceInitCtrlService.java index d39c754..1aaec9b 100644 --- a/src/main/java/a8k/app/service/mainctrl/AppDeviceInitCtrlService.java +++ b/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; } diff --git a/src/main/java/a8k/app/service/module/SamplePreProcessModule.java b/src/main/java/a8k/app/service/module/SamplePreProcessModule.java index 8820190..5a6289d 100644 --- a/src/main/java/a8k/app/service/module/SamplePreProcessModule.java +++ b/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 cxts = tube.getPreProcessContexts(); diff --git a/src/main/java/a8k/app/service/setting/AppSettingsMgrService.java b/src/main/java/a8k/app/service/setting/AppSettingsMgrService.java index 54dfba7..82cd9b9 100644 --- a/src/main/java/a8k/app/service/setting/AppSettingsMgrService.java +++ b/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); } diff --git a/src/main/java/a8k/app/service/statemgr/AppFlagStateMgr.java b/src/main/java/a8k/app/service/statemgr/AppFlagStateMgr.java index 8144d67..d1abd87 100644 --- a/src/main/java/a8k/app/service/statemgr/AppFlagStateMgr.java +++ b/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 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); } -} +} \ No newline at end of file diff --git a/src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java b/src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java index 2ad78f9..5c854e7 100644 --- a/src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java +++ b/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); + } } //更新耗材 diff --git a/src/main/java/a8k/app/service/statemgr/DeviceWorkStateMgrService.java b/src/main/java/a8k/app/service/statemgr/DeviceWorkStateMgrService.java index 3e270b1..f0f03c0 100644 --- a/src/main/java/a8k/app/service/statemgr/DeviceWorkStateMgrService.java +++ b/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; - } } diff --git a/src/main/java/a8k/app/service/statemgr/GStateMgrService.java b/src/main/java/a8k/app/service/statemgr/GStateMgrService.java index 245fef1..07aade1 100644 --- a/src/main/java/a8k/app/service/statemgr/GStateMgrService.java +++ b/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; } diff --git a/src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgr.java b/src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgr.java index a295826..e002992 100644 --- a/src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgr.java +++ b/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]; } diff --git a/src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java b/src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java index fc51e62..e38c93f 100644 --- a/src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java +++ b/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++; } diff --git a/src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java b/src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java index 468b5fa..aa2670e 100644 --- a/src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java +++ b/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); diff --git a/src/main/java/a8k/app/service/statemgr/TubeStateMgr.java b/src/main/java/a8k/app/service/statemgr/TubeStateMgr.java index 726ace6..dd9b5a0 100644 --- a/src/main/java/a8k/app/service/statemgr/TubeStateMgr.java +++ b/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); + + } + } diff --git a/src/main/java/a8k/app/type/DeviceWarningFlagStateGroup.java b/src/main/java/a8k/app/type/DeviceWarningFlagStateGroup.java new file mode 100644 index 0000000..6a46388 --- /dev/null +++ b/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 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 + } +} diff --git a/src/main/java/a8k/app/type/GState.java b/src/main/java/a8k/app/type/GState.java index c575a3b..ecc7010 100644 --- a/src/main/java/a8k/app/type/GState.java +++ b/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; // diff --git a/src/main/java/a8k/app/type/a8k/state/Tube.java b/src/main/java/a8k/app/type/a8k/state/Tube.java index 88292a8..8227db0 100644 --- a/src/main/java/a8k/app/type/a8k/state/Tube.java +++ b/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; diff --git a/src/main/java/a8k/app/type/a8k/state/TubeHolder.java b/src/main/java/a8k/app/type/a8k/state/TubeHolder.java index db445b0..494f608 100644 --- a/src/main/java/a8k/app/type/a8k/state/TubeHolder.java +++ b/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) { diff --git a/src/main/java/a8k/app/type/appevent/AppLoginEvent.java b/src/main/java/a8k/app/type/appevent/AppLoginEvent.java new file mode 100644 index 0000000..83c5720 --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/a8k/app/type/lisprotocol/BiLisDoubleTrackFrame.java b/src/main/java/a8k/app/type/lisprotocol/BiLisDoubleTrackFrame.java index 804c5d6..9ad346f 100644 --- a/src/main/java/a8k/app/type/lisprotocol/BiLisDoubleTrackFrame.java +++ b/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 diff --git a/src/main/java/a8k/app/type/lisprotocol/BiLisDoubleTrackFrameBuildContext.java b/src/main/java/a8k/app/type/lisprotocol/BiLisDoubleTrackFrameBuildContext.java new file mode 100644 index 0000000..c173c72 --- /dev/null +++ b/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; + +} diff --git a/src/main/java/a8k/extui/page/debug/P12TueStateDebugPage.java b/src/main/java/a8k/extui/page/debug/P12TueStateDebugPage.java index 9801353..818505f 100644 --- a/src/main/java/a8k/extui/page/debug/P12TueStateDebugPage.java +++ b/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]; } diff --git a/src/test/java/a8k/app/factory/BiLisDoubleTrackFrameFactoryTest.java b/src/test/java/a8k/app/factory/BiLisDoubleTrackFrameFactoryTest.java new file mode 100644 index 0000000..066b71e --- /dev/null +++ b/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() { + } +} \ No newline at end of file diff --git a/代码说明/20240718.txt b/代码说明/20240718.txt deleted file mode 100644 index 1ad5db5..0000000 --- a/代码说明/20240718.txt +++ /dev/null @@ -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 方法 - ``` \ No newline at end of file