From c9af5d98a121cbd59df00842d9b56c35442725c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E5=87=A4=E5=90=89?= Date: Thu, 24 Jul 2025 11:22:44 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E4=BC=98=E5=8C=96=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=8E=A8=E9=80=81=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/controller/TestController.java | 8 +++- .../app/core/aspect/DeviceStateChangeAspect.java | 45 ++++++++++++++++++++ .../app/core/event/StateChangeEvent.java | 14 +++++++ .../colortitration/app/core/state/DeviceState.java | 48 ++++++++++++++++++++++ .../app/core/state/HeatModuleState.java | 41 ++++++++++++++++++ .../app/websocket/server/WebsocketResult.java | 3 ++ 6 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/iflytop/colortitration/app/core/aspect/DeviceStateChangeAspect.java create mode 100644 src/main/java/com/iflytop/colortitration/app/core/event/StateChangeEvent.java create mode 100644 src/main/java/com/iflytop/colortitration/app/core/state/DeviceState.java create mode 100644 src/main/java/com/iflytop/colortitration/app/core/state/HeatModuleState.java diff --git a/src/main/java/com/iflytop/colortitration/app/controller/TestController.java b/src/main/java/com/iflytop/colortitration/app/controller/TestController.java index f6233ff..61b1557 100644 --- a/src/main/java/com/iflytop/colortitration/app/controller/TestController.java +++ b/src/main/java/com/iflytop/colortitration/app/controller/TestController.java @@ -1,5 +1,7 @@ package com.iflytop.colortitration.app.controller; +import com.iflytop.colortitration.app.core.state.DeviceState; +import com.iflytop.colortitration.app.service.TestService; import com.iflytop.colortitration.common.result.Result; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -12,16 +14,20 @@ import org.springframework.web.bind.annotation.RestController; /** * 测试用 */ -@Tag(name = "测试用") +@Tag(name = "⭐测试用") @RestController @RequestMapping("/api/test") @RequiredArgsConstructor @Slf4j public class TestController { + private final TestService testService; + private final DeviceState deviceState; @Operation(summary = "启动虚拟模式") @PostMapping("/virtual") public Result changeVirtualMode() { + deviceState.setVirtual(true); return Result.success(); } + } diff --git a/src/main/java/com/iflytop/colortitration/app/core/aspect/DeviceStateChangeAspect.java b/src/main/java/com/iflytop/colortitration/app/core/aspect/DeviceStateChangeAspect.java new file mode 100644 index 0000000..164564c --- /dev/null +++ b/src/main/java/com/iflytop/colortitration/app/core/aspect/DeviceStateChangeAspect.java @@ -0,0 +1,45 @@ +package com.iflytop.colortitration.app.core.aspect; + +import com.iflytop.colortitration.app.core.state.DeviceState; +import com.iflytop.colortitration.app.websocket.server.WebSocketMessageType; +import com.iflytop.colortitration.app.websocket.server.WebSocketSender; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.stereotype.Component; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +@Slf4j +@Aspect +@Component +@RequiredArgsConstructor +public class DeviceStateChangeAspect { + private final WebSocketSender webSocketService; + private final DeviceState deviceState; + + private final Lock lock = new ReentrantLock(); + + @Before("execution(* com.iflytop.colortitration.app.core.state.*.set*(..))") + public void beforeSetMethod(JoinPoint joinPoint) { + lock.lock(); + } + + @After("execution(* com.iflytop.colortitration.app.core.state.*.set*(..))") + public void afterSetMethod(JoinPoint joinPoint) { + try { + Object[] methodArgs = joinPoint.getArgs(); + if (methodArgs != null && methodArgs.length > 0) { + webSocketService.push(WebSocketMessageType.STATUS, deviceState.toJSON()); + } + } catch (Exception e) { + log.error("处理状态变更后的值失败", e); + } finally { + lock.unlock(); + } + } +} diff --git a/src/main/java/com/iflytop/colortitration/app/core/event/StateChangeEvent.java b/src/main/java/com/iflytop/colortitration/app/core/event/StateChangeEvent.java new file mode 100644 index 0000000..d1926f7 --- /dev/null +++ b/src/main/java/com/iflytop/colortitration/app/core/event/StateChangeEvent.java @@ -0,0 +1,14 @@ +package com.iflytop.colortitration.app.core.event; +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * 状态变更事件 + */ +@Data +@AllArgsConstructor +public class StateChangeEvent { + private String fieldPath; + private Object oldValue; + private Object newValue; +} diff --git a/src/main/java/com/iflytop/colortitration/app/core/state/DeviceState.java b/src/main/java/com/iflytop/colortitration/app/core/state/DeviceState.java new file mode 100644 index 0000000..b906e18 --- /dev/null +++ b/src/main/java/com/iflytop/colortitration/app/core/state/DeviceState.java @@ -0,0 +1,48 @@ +package com.iflytop.colortitration.app.core.state; + +import cn.hutool.json.JSONObject; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.iflytop.colortitration.common.enums.Device; +import com.iflytop.colortitration.common.model.entity.User; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +@Schema(description = "设备当前状态") +@Data +@Component +@JsonIgnoreProperties(value = {"advisors", "frozen", "preFiltered", "proxyTargetClass", "targetSource", "exposeProxy", "advisorCount", "proxiedInterfaces", "targetClass"}) +public class DeviceState { + @Schema(description = "加热模块属性") + private Map heatModule = new HashMap<>(); + + @Schema(description = "虚拟模式,true为虚拟") + private boolean virtual = false; + + @Schema(description = "初始化状态,true初始化完毕") + private boolean initComplete = false; + + @Schema(description = "自检状态,true自检完毕") + private boolean selfTest = false; + + @Schema(description = "是否是急停状态,true为急停") + private boolean emergencyStop = false; + + @Schema(description = "当前登录用户") + private User currentUser; + + public JSONObject toJSON() { + JSONObject json = new JSONObject(); + json.putOnce("heatModule", new ArrayList<>(heatModule.values())); + json.putOnce("virtual", virtual); + json.putOnce("initComplete", initComplete); + json.putOnce("selfTest", selfTest); + json.putOnce("emergencyStop", emergencyStop); + json.putOnce("currentUser", currentUser); + return json; + } +} \ No newline at end of file diff --git a/src/main/java/com/iflytop/colortitration/app/core/state/HeatModuleState.java b/src/main/java/com/iflytop/colortitration/app/core/state/HeatModuleState.java new file mode 100644 index 0000000..79579ed --- /dev/null +++ b/src/main/java/com/iflytop/colortitration/app/core/state/HeatModuleState.java @@ -0,0 +1,41 @@ +package com.iflytop.colortitration.app.core.state; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.iflytop.colortitration.common.enums.Device; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +@Schema(description = "当前加热模块状态") +@Data +@Component +@Scope("prototype") +@RequiredArgsConstructor +@JsonIgnoreProperties(value = {"advisors", "frozen", "preFiltered", "proxyTargetClass", "targetSource", "exposeProxy", "advisorCount", "proxiedInterfaces", "targetClass"}) +public class HeatModuleState { + @Schema(description = "加热模块code") + private Device deviceCode; + + @Schema(description = "是否启动加热,true为正在加热,false为未在加热") + private boolean open = false; + + @Schema(description = "加热器当前温度") + private Double temperature = null; + + @Schema(description = "加热器目标温度") + private Double targetTemperature = null; + + @Schema(description = "加热器目标加热时间,单位秒") + private Integer targetTime = null; + + @Schema(description = "开始加热的时间") + private LocalDateTime startHeatTime = null; + + public HeatModuleState(Device deviceCode) { + this.deviceCode = deviceCode; + } +} diff --git a/src/main/java/com/iflytop/colortitration/app/websocket/server/WebsocketResult.java b/src/main/java/com/iflytop/colortitration/app/websocket/server/WebsocketResult.java index a8a74f3..a2f083e 100644 --- a/src/main/java/com/iflytop/colortitration/app/websocket/server/WebsocketResult.java +++ b/src/main/java/com/iflytop/colortitration/app/websocket/server/WebsocketResult.java @@ -15,4 +15,7 @@ public class WebsocketResult { */ @Schema(description = "推送数据") private Object data; + + @Schema(description = "推送时间戳") + private Long timestamp; } \ No newline at end of file