commit
e66b4fb670
134 changed files with 5469 additions and 0 deletions
-
3.gitattributes
-
38.gitignore
-
58build.gradle
-
BINgradle/wrapper/gradle-wrapper.jar
-
7gradle/wrapper/gradle-wrapper.properties
-
252gradlew
-
94gradlew.bat
-
BINmatrix-spray.db
-
1settings.gradle
-
95sql/init.sql
-
15src/main/java/com/qyft/ms/MatrixSprayApplication.java
-
117src/main/java/com/qyft/ms/common/constant/Commands.java
-
27src/main/java/com/qyft/ms/common/constant/SysSettings.java
-
25src/main/java/com/qyft/ms/common/constant/WebSocketMessageType.java
-
27src/main/java/com/qyft/ms/common/result/CMDResultCode.java
-
14src/main/java/com/qyft/ms/config/WebSocketConfig.java
-
59src/main/java/com/qyft/ms/config/WebSocketServer.java
-
47src/main/java/com/qyft/ms/controller/CMDController.java
-
55src/main/java/com/qyft/ms/controller/LogsController.java
-
56src/main/java/com/qyft/ms/controller/SysSettingsController.java
-
160src/main/java/com/qyft/ms/device/client/TcpClient.java
-
38src/main/java/com/qyft/ms/device/common/constant/DeviceCommands.java
-
16src/main/java/com/qyft/ms/device/common/constant/TcpMessageType.java
-
24src/main/java/com/qyft/ms/device/common/jsonrpc/JsonRpcRequest.java
-
16src/main/java/com/qyft/ms/device/common/jsonrpc/JsonRpcResponse.java
-
37src/main/java/com/qyft/ms/device/config/TcpConfig.java
-
37src/main/java/com/qyft/ms/device/controller/DeviceController.java
-
93src/main/java/com/qyft/ms/device/controller/DeviceCtrlController.java
-
43src/main/java/com/qyft/ms/device/controller/TestController.java
-
68src/main/java/com/qyft/ms/device/handler/DeviceMessageHandler.java
-
11src/main/java/com/qyft/ms/device/mapper/CtrlFuncMapper.java
-
11src/main/java/com/qyft/ms/device/mapper/CtrlFuncStepMapper.java
-
18src/main/java/com/qyft/ms/device/model/bo/DeviceAlarm.java
-
27src/main/java/com/qyft/ms/device/model/bo/DeviceCtrlFuncCMD.java
-
26src/main/java/com/qyft/ms/device/model/bo/DeviceFeedback.java
-
38src/main/java/com/qyft/ms/device/model/bo/DeviceOperationalStatus.java
-
140src/main/java/com/qyft/ms/device/model/bo/DeviceStatus.java
-
23src/main/java/com/qyft/ms/device/model/entity/CtrlFunc.java
-
27src/main/java/com/qyft/ms/device/model/entity/CtrlFuncStep.java
-
38src/main/java/com/qyft/ms/device/model/form/CtrlFuncForm.java
-
26src/main/java/com/qyft/ms/device/model/vo/CtrlFuncVO.java
-
26src/main/java/com/qyft/ms/device/model/vo/DeviceCtrlFuncVO.java
-
12src/main/java/com/qyft/ms/device/service/DeviceAlarmService.java
-
14src/main/java/com/qyft/ms/device/service/DeviceService.java
-
47src/main/java/com/qyft/ms/device/service/DeviceStatusService.java
-
166src/main/java/com/qyft/ms/device/service/DeviceStepService.java
-
261src/main/java/com/qyft/ms/device/service/DeviceTcpCMDService.java
-
28src/main/java/com/qyft/ms/device/service/ICtrlFuncService.java
-
12src/main/java/com/qyft/ms/device/service/ICtrlFuncStepService.java
-
132src/main/java/com/qyft/ms/device/service/impl/CtrlFuncServiceImpl.java
-
20src/main/java/com/qyft/ms/device/service/impl/CtrlFuncStepServiceImpl.java
-
34src/main/java/com/qyft/ms/enums/DirectiveTypeEnum.java
-
28src/main/java/com/qyft/ms/generator/CodeGenerator.java
-
12src/main/java/com/qyft/ms/mapper/LogsMapper.java
-
29src/main/java/com/qyft/ms/mapper/SysSettingsMapper.java
-
52src/main/java/com/qyft/ms/model/bo/CraftsStepMethod.java
-
35src/main/java/com/qyft/ms/model/bo/CraftsStepStatus.java
-
23src/main/java/com/qyft/ms/model/bo/TubeSol.java
-
14src/main/java/com/qyft/ms/model/dto/BaseDataDTO.java
-
13src/main/java/com/qyft/ms/model/dto/CmdInjectFluidDTO.java
-
14src/main/java/com/qyft/ms/model/dto/ContainerDTO.java
-
14src/main/java/com/qyft/ms/model/dto/InjectFluid.java
-
10src/main/java/com/qyft/ms/model/dto/LogDTO.java
-
11src/main/java/com/qyft/ms/model/dto/PauseCraftsDto.java
-
11src/main/java/com/qyft/ms/model/dto/ResumeCraftsDto.java
-
13src/main/java/com/qyft/ms/model/dto/StartCraftsDTO.java
-
13src/main/java/com/qyft/ms/model/dto/StartHeatDTO.java
-
11src/main/java/com/qyft/ms/model/dto/StopCraftsDto.java
-
10src/main/java/com/qyft/ms/model/dto/StopTaskDTO.java
-
16src/main/java/com/qyft/ms/model/dto/SysSettingsDTO.java
-
10src/main/java/com/qyft/ms/model/dto/TaskDTO.java
-
22src/main/java/com/qyft/ms/model/dto/WebsocketDTO.java
-
35src/main/java/com/qyft/ms/model/entity/Container.java
-
25src/main/java/com/qyft/ms/model/entity/Crafts.java
-
30src/main/java/com/qyft/ms/model/entity/Logs.java
-
20src/main/java/com/qyft/ms/model/entity/Ores.java
-
20src/main/java/com/qyft/ms/model/entity/Solutions.java
-
43src/main/java/com/qyft/ms/model/entity/SysSettings.java
-
30src/main/java/com/qyft/ms/model/entity/TaskSteps.java
-
35src/main/java/com/qyft/ms/model/entity/Tasks.java
-
23src/main/java/com/qyft/ms/model/form/CMDForm.java
-
27src/main/java/com/qyft/ms/model/vo/BaseDataVO.java
-
13src/main/java/com/qyft/ms/model/vo/ContainerListVO.java
-
23src/main/java/com/qyft/ms/model/vo/CraftsStepResult.java
-
22src/main/java/com/qyft/ms/model/vo/ExecutionResult.java
-
30src/main/java/com/qyft/ms/model/vo/OresCraftsListVO.java
-
14src/main/java/com/qyft/ms/model/vo/SysSettingResult.java
-
43src/main/java/com/qyft/ms/model/vo/SysSettingVO.java
-
35src/main/java/com/qyft/ms/model/vo/TaskListVO.java
-
18src/main/java/com/qyft/ms/model/vo/WebsocketResult.java
-
61src/main/java/com/qyft/ms/service/CMDService.java
-
11src/main/java/com/qyft/ms/service/ILogsService.java
-
24src/main/java/com/qyft/ms/service/ISysSettingsService.java
-
38src/main/java/com/qyft/ms/service/StatusService.java
-
32src/main/java/com/qyft/ms/service/WebSocketService.java
-
29src/main/java/com/qyft/ms/service/impl/ILogsServiceImpl.java
-
75src/main/java/com/qyft/ms/service/impl/ISysSettingsServiceImpl.java
-
44src/main/java/com/qyft/ms/system/common/base/BaseEntity.java
-
26src/main/java/com/qyft/ms/system/common/base/BasePageQuery.java
-
84src/main/java/com/qyft/ms/system/common/base/IBaseEnum.java
@ -0,0 +1,3 @@ |
|||
/gradlew text eol=lf |
|||
*.bat text eol=crlf |
|||
*.jar binary |
@ -0,0 +1,38 @@ |
|||
.gradle |
|||
build/ |
|||
logs/ |
|||
!gradle/wrapper/gradle-wrapper.jar |
|||
!**/src/main/**/build/ |
|||
!**/src/test/**/build/ |
|||
|
|||
### STS ### |
|||
.apt_generated |
|||
.classpath |
|||
.factorypath |
|||
.project |
|||
.settings |
|||
.springBeans |
|||
.sts4-cache |
|||
bin/ |
|||
!**/src/main/**/bin/ |
|||
!**/src/test/**/bin/ |
|||
|
|||
### IntelliJ IDEA ### |
|||
.idea |
|||
*.iws |
|||
*.iml |
|||
*.ipr |
|||
out/ |
|||
!**/src/main/**/out/ |
|||
!**/src/test/**/out/ |
|||
|
|||
### NetBeans ### |
|||
/nbproject/private/ |
|||
/nbbuild/ |
|||
/dist/ |
|||
/nbdist/ |
|||
/.nb-gradle/ |
|||
|
|||
### VS Code ### |
|||
.vscode/ |
|||
|
@ -0,0 +1,58 @@ |
|||
plugins { |
|||
id 'java' |
|||
id 'org.springframework.boot' version '3.3.8' |
|||
id 'io.spring.dependency-management' version '1.1.7' |
|||
} |
|||
|
|||
group = 'com.qyft' |
|||
version = '0.0.1' |
|||
|
|||
java { |
|||
toolchain { |
|||
languageVersion = JavaLanguageVersion.of(17) |
|||
} |
|||
} |
|||
|
|||
configurations { |
|||
compileOnly { |
|||
extendsFrom annotationProcessor |
|||
} |
|||
} |
|||
|
|||
repositories { |
|||
mavenCentral() |
|||
} |
|||
|
|||
dependencies { |
|||
implementation 'org.springframework.boot:spring-boot-starter-web' |
|||
implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.5.16' |
|||
implementation group: 'org.xerial', name: 'sqlite-jdbc', version: '3.48.0.0' |
|||
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.4' |
|||
implementation group: 'org.freemarker', name: 'freemarker', version: '2.3.34' |
|||
implementation group: 'com.baomidou', name: 'mybatis-plus-boot-starter', version: '3.5.10.1' |
|||
implementation group: 'com.baomidou', name: 'mybatis-plus-jsqlparser', version: '3.5.10.1' |
|||
implementation group: 'com.baomidou', name: 'mybatis-plus-generator', version: '3.5.10.1' |
|||
implementation group: 'cn.hutool', name: 'hutool-all', version: '5.8.35' |
|||
implementation group: 'com.github.xiaoymin', name: 'knife4j-openapi3-jakarta-spring-boot-starter', version: '4.5.0' |
|||
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.12.6' |
|||
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.12.6' |
|||
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.12.6' |
|||
implementation group: 'com.alibaba', name: 'fastjson', version: '2.0.54' |
|||
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-websocket', version: '3.4.2' |
|||
implementation group: 'io.netty', name: 'netty-all', version: '4.1.118.Final' |
|||
|
|||
//++++++++项目级别的放到下面++++++++ |
|||
|
|||
//++++++++项目级别的放到上面++++++++ |
|||
|
|||
compileOnly 'org.projectlombok:lombok' |
|||
developmentOnly 'org.springframework.boot:spring-boot-devtools' |
|||
annotationProcessor 'org.projectlombok:lombok' |
|||
testImplementation 'org.springframework.boot:spring-boot-starter-test' |
|||
testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.4' |
|||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher' |
|||
} |
|||
|
|||
tasks.named('test') { |
|||
useJUnitPlatform() |
|||
} |
@ -0,0 +1,7 @@ |
|||
distributionBase=GRADLE_USER_HOME |
|||
distributionPath=wrapper/dists |
|||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip |
|||
networkTimeout=10000 |
|||
validateDistributionUrl=true |
|||
zipStoreBase=GRADLE_USER_HOME |
|||
zipStorePath=wrapper/dists |
@ -0,0 +1,252 @@ |
|||
#!/bin/sh |
|||
|
|||
# |
|||
# Copyright © 2015-2021 the original authors. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# https://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
# |
|||
# SPDX-License-Identifier: Apache-2.0 |
|||
# |
|||
|
|||
############################################################################## |
|||
# |
|||
# Gradle start up script for POSIX generated by Gradle. |
|||
# |
|||
# Important for running: |
|||
# |
|||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is |
|||
# noncompliant, but you have some other compliant shell such as ksh or |
|||
# bash, then to run this script, type that shell name before the whole |
|||
# command line, like: |
|||
# |
|||
# ksh Gradle |
|||
# |
|||
# Busybox and similar reduced shells will NOT work, because this script |
|||
# requires all of these POSIX shell features: |
|||
# * functions; |
|||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», |
|||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»; |
|||
# * compound commands having a testable exit status, especially «case»; |
|||
# * various built-in commands including «command», «set», and «ulimit». |
|||
# |
|||
# Important for patching: |
|||
# |
|||
# (2) This script targets any POSIX shell, so it avoids extensions provided |
|||
# by Bash, Ksh, etc; in particular arrays are avoided. |
|||
# |
|||
# The "traditional" practice of packing multiple parameters into a |
|||
# space-separated string is a well documented source of bugs and security |
|||
# problems, so this is (mostly) avoided, by progressively accumulating |
|||
# options in "$@", and eventually passing that to Java. |
|||
# |
|||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, |
|||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; |
|||
# see the in-line comments for details. |
|||
# |
|||
# There are tweaks for specific operating systems such as AIX, CygWin, |
|||
# Darwin, MinGW, and NonStop. |
|||
# |
|||
# (3) This script is generated from the Groovy template |
|||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt |
|||
# within the Gradle project. |
|||
# |
|||
# You can find Gradle at https://github.com/gradle/gradle/. |
|||
# |
|||
############################################################################## |
|||
|
|||
# Attempt to set APP_HOME |
|||
|
|||
# Resolve links: $0 may be a link |
|||
app_path=$0 |
|||
|
|||
# Need this for daisy-chained symlinks. |
|||
while |
|||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path |
|||
[ -h "$app_path" ] |
|||
do |
|||
ls=$( ls -ld "$app_path" ) |
|||
link=${ls#*' -> '} |
|||
case $link in #( |
|||
/*) app_path=$link ;; #( |
|||
*) app_path=$APP_HOME$link ;; |
|||
esac |
|||
done |
|||
|
|||
# This is normally unused |
|||
# shellcheck disable=SC2034 |
|||
APP_BASE_NAME=${0##*/} |
|||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) |
|||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s |
|||
' "$PWD" ) || exit |
|||
|
|||
# Use the maximum available, or set MAX_FD != -1 to use that value. |
|||
MAX_FD=maximum |
|||
|
|||
warn () { |
|||
echo "$*" |
|||
} >&2 |
|||
|
|||
die () { |
|||
echo |
|||
echo "$*" |
|||
echo |
|||
exit 1 |
|||
} >&2 |
|||
|
|||
# OS specific support (must be 'true' or 'false'). |
|||
cygwin=false |
|||
msys=false |
|||
darwin=false |
|||
nonstop=false |
|||
case "$( uname )" in #( |
|||
CYGWIN* ) cygwin=true ;; #( |
|||
Darwin* ) darwin=true ;; #( |
|||
MSYS* | MINGW* ) msys=true ;; #( |
|||
NONSTOP* ) nonstop=true ;; |
|||
esac |
|||
|
|||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar |
|||
|
|||
|
|||
# Determine the Java command to use to start the JVM. |
|||
if [ -n "$JAVA_HOME" ] ; then |
|||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then |
|||
# IBM's JDK on AIX uses strange locations for the executables |
|||
JAVACMD=$JAVA_HOME/jre/sh/java |
|||
else |
|||
JAVACMD=$JAVA_HOME/bin/java |
|||
fi |
|||
if [ ! -x "$JAVACMD" ] ; then |
|||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME |
|||
|
|||
Please set the JAVA_HOME variable in your environment to match the |
|||
location of your Java installation." |
|||
fi |
|||
else |
|||
JAVACMD=java |
|||
if ! command -v java >/dev/null 2>&1 |
|||
then |
|||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
|||
|
|||
Please set the JAVA_HOME variable in your environment to match the |
|||
location of your Java installation." |
|||
fi |
|||
fi |
|||
|
|||
# Increase the maximum file descriptors if we can. |
|||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then |
|||
case $MAX_FD in #( |
|||
max*) |
|||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. |
|||
# shellcheck disable=SC2039,SC3045 |
|||
MAX_FD=$( ulimit -H -n ) || |
|||
warn "Could not query maximum file descriptor limit" |
|||
esac |
|||
case $MAX_FD in #( |
|||
'' | soft) :;; #( |
|||
*) |
|||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. |
|||
# shellcheck disable=SC2039,SC3045 |
|||
ulimit -n "$MAX_FD" || |
|||
warn "Could not set maximum file descriptor limit to $MAX_FD" |
|||
esac |
|||
fi |
|||
|
|||
# Collect all arguments for the java command, stacking in reverse order: |
|||
# * args from the command line |
|||
# * the main class name |
|||
# * -classpath |
|||
# * -D...appname settings |
|||
# * --module-path (only if needed) |
|||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. |
|||
|
|||
# For Cygwin or MSYS, switch paths to Windows format before running java |
|||
if "$cygwin" || "$msys" ; then |
|||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) |
|||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) |
|||
|
|||
JAVACMD=$( cygpath --unix "$JAVACMD" ) |
|||
|
|||
# Now convert the arguments - kludge to limit ourselves to /bin/sh |
|||
for arg do |
|||
if |
|||
case $arg in #( |
|||
-*) false ;; # don't mess with options #( |
|||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath |
|||
[ -e "$t" ] ;; #( |
|||
*) false ;; |
|||
esac |
|||
then |
|||
arg=$( cygpath --path --ignore --mixed "$arg" ) |
|||
fi |
|||
# Roll the args list around exactly as many times as the number of |
|||
# args, so each arg winds up back in the position where it started, but |
|||
# possibly modified. |
|||
# |
|||
# NB: a `for` loop captures its iteration list before it begins, so |
|||
# changing the positional parameters here affects neither the number of |
|||
# iterations, nor the values presented in `arg`. |
|||
shift # remove old arg |
|||
set -- "$@" "$arg" # push replacement arg |
|||
done |
|||
fi |
|||
|
|||
|
|||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
|||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' |
|||
|
|||
# Collect all arguments for the java command: |
|||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, |
|||
# and any embedded shellness will be escaped. |
|||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be |
|||
# treated as '${Hostname}' itself on the command line. |
|||
|
|||
set -- \ |
|||
"-Dorg.gradle.appname=$APP_BASE_NAME" \ |
|||
-classpath "$CLASSPATH" \ |
|||
org.gradle.wrapper.GradleWrapperMain \ |
|||
"$@" |
|||
|
|||
# Stop when "xargs" is not available. |
|||
if ! command -v xargs >/dev/null 2>&1 |
|||
then |
|||
die "xargs is not available" |
|||
fi |
|||
|
|||
# Use "xargs" to parse quoted args. |
|||
# |
|||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed. |
|||
# |
|||
# In Bash we could simply go: |
|||
# |
|||
# readarray ARGS < <( xargs -n1 <<<"$var" ) && |
|||
# set -- "${ARGS[@]}" "$@" |
|||
# |
|||
# but POSIX shell has neither arrays nor command substitution, so instead we |
|||
# post-process each arg (as a line of input to sed) to backslash-escape any |
|||
# character that might be a shell metacharacter, then use eval to reverse |
|||
# that process (while maintaining the separation between arguments), and wrap |
|||
# the whole thing up as a single "set" statement. |
|||
# |
|||
# This will of course break if any of these variables contains a newline or |
|||
# an unmatched quote. |
|||
# |
|||
|
|||
eval "set -- $( |
|||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | |
|||
xargs -n1 | |
|||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | |
|||
tr '\n' ' ' |
|||
)" '"$@"' |
|||
|
|||
exec "$JAVACMD" "$@" |
@ -0,0 +1,94 @@ |
|||
@rem |
|||
@rem Copyright 2015 the original author or authors. |
|||
@rem |
|||
@rem Licensed under the Apache License, Version 2.0 (the "License"); |
|||
@rem you may not use this file except in compliance with the License. |
|||
@rem You may obtain a copy of the License at |
|||
@rem |
|||
@rem https://www.apache.org/licenses/LICENSE-2.0 |
|||
@rem |
|||
@rem Unless required by applicable law or agreed to in writing, software |
|||
@rem distributed under the License is distributed on an "AS IS" BASIS, |
|||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
@rem See the License for the specific language governing permissions and |
|||
@rem limitations under the License. |
|||
@rem |
|||
@rem SPDX-License-Identifier: Apache-2.0 |
|||
@rem |
|||
|
|||
@if "%DEBUG%"=="" @echo off |
|||
@rem ########################################################################## |
|||
@rem |
|||
@rem Gradle startup script for Windows |
|||
@rem |
|||
@rem ########################################################################## |
|||
|
|||
@rem Set local scope for the variables with windows NT shell |
|||
if "%OS%"=="Windows_NT" setlocal |
|||
|
|||
set DIRNAME=%~dp0 |
|||
if "%DIRNAME%"=="" set DIRNAME=. |
|||
@rem This is normally unused |
|||
set APP_BASE_NAME=%~n0 |
|||
set APP_HOME=%DIRNAME% |
|||
|
|||
@rem Resolve any "." and ".." in APP_HOME to make it shorter. |
|||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi |
|||
|
|||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
|||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" |
|||
|
|||
@rem Find java.exe |
|||
if defined JAVA_HOME goto findJavaFromJavaHome |
|||
|
|||
set JAVA_EXE=java.exe |
|||
%JAVA_EXE% -version >NUL 2>&1 |
|||
if %ERRORLEVEL% equ 0 goto execute |
|||
|
|||
echo. 1>&2 |
|||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 |
|||
echo. 1>&2 |
|||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2 |
|||
echo location of your Java installation. 1>&2 |
|||
|
|||
goto fail |
|||
|
|||
:findJavaFromJavaHome |
|||
set JAVA_HOME=%JAVA_HOME:"=% |
|||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe |
|||
|
|||
if exist "%JAVA_EXE%" goto execute |
|||
|
|||
echo. 1>&2 |
|||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 |
|||
echo. 1>&2 |
|||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2 |
|||
echo location of your Java installation. 1>&2 |
|||
|
|||
goto fail |
|||
|
|||
:execute |
|||
@rem Setup the command line |
|||
|
|||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar |
|||
|
|||
|
|||
@rem Execute Gradle |
|||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* |
|||
|
|||
:end |
|||
@rem End local scope for the variables with windows NT shell |
|||
if %ERRORLEVEL% equ 0 goto mainEnd |
|||
|
|||
:fail |
|||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of |
|||
rem the _cmd.exe /c_ return code! |
|||
set EXIT_CODE=%ERRORLEVEL% |
|||
if %EXIT_CODE% equ 0 set EXIT_CODE=1 |
|||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% |
|||
exit /b %EXIT_CODE% |
|||
|
|||
:mainEnd |
|||
if "%OS%"=="Windows_NT" endlocal |
|||
|
|||
:omega |
@ -0,0 +1 @@ |
|||
rootProject.name = 'matrix-spray' |
@ -0,0 +1,95 @@ |
|||
-- 创建 sys_user 表 |
|||
CREATE TABLE IF NOT EXISTS sys_user |
|||
( |
|||
id INTEGER PRIMARY KEY AUTOINCREMENT, |
|||
username TEXT NOT NULL, |
|||
nickname TEXT, |
|||
password TEXT NOT NULL, |
|||
role_id INTEGER, |
|||
is_deleted TINYINT DEFAULT 0, |
|||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
|||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP |
|||
); |
|||
|
|||
-- 插入测试数据 |
|||
INSERT INTO sys_user (username, nickname, password, role_id, is_deleted) |
|||
VALUES ('admin', 'Admin', '12345', 1, 0), |
|||
('john_doe', 'John Doe', 'password123', 2, 0), |
|||
('test', 'test', 'test123', 3, 0); |
|||
|
|||
|
|||
-- 创建 sys_role 表 |
|||
CREATE TABLE IF NOT EXISTS sys_role |
|||
( |
|||
id INTEGER PRIMARY KEY AUTOINCREMENT, |
|||
name TEXT NOT NULL, |
|||
code TEXT NOT NULL, |
|||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
|||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP |
|||
); |
|||
|
|||
-- 插入角色数据 |
|||
INSERT INTO sys_role (name, code) |
|||
VALUES ('管理员', 'ADMIN'), |
|||
('普通用户', 'USER'), |
|||
('测试用户', 'TEST'); |
|||
|
|||
-- 创建 matrix 基质类型表 |
|||
CREATE TABLE IF NOT EXISTS matrix |
|||
( |
|||
id INTEGER PRIMARY KEY AUTOINCREMENT, |
|||
name TEXT NOT NULL, |
|||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
|||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP |
|||
); |
|||
|
|||
-- 创建 matrix_craft 基质工艺表 |
|||
CREATE TABLE IF NOT EXISTS matrix_craft |
|||
( |
|||
id INTEGER PRIMARY KEY AUTOINCREMENT, |
|||
name TEXT NOT NULL, |
|||
matrix_id INTEGER NOT NULL, |
|||
route_type INTEGER, |
|||
z_height INTEGER, |
|||
nitrogen_flow_velocity INTEGER, |
|||
nitrogen_air_pressure INTEGER, |
|||
matrix_flow_velocity INTEGER, |
|||
voltage INTEGER, |
|||
movement_speed INTEGER, |
|||
space INTEGER, |
|||
create_user INTEGER, |
|||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
|||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP |
|||
); |
|||
|
|||
-- 创建 syringe 注射器表 |
|||
CREATE TABLE IF NOT EXISTS syringe |
|||
( |
|||
id INTEGER PRIMARY KEY AUTOINCREMENT, |
|||
flow_rate INTEGER, |
|||
fluid_volume INTEGER, |
|||
run_time INTEGER, |
|||
cycle_intervals INTEGER |
|||
); |
|||
|
|||
-- 创建 operation_log 操作记录表 |
|||
CREATE TABLE IF NOT EXISTS operation_log |
|||
( |
|||
id INTEGER PRIMARY KEY AUTOINCREMENT, |
|||
matrix_craft_id INTEGER, |
|||
matrix_info TEXT, |
|||
status INTEGER, |
|||
create_user INTEGER, |
|||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
|||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP |
|||
); |
|||
|
|||
-- 创建 sys_settings 系统配置表 |
|||
CREATE TABLE IF NOT EXISTS sys_settings |
|||
( |
|||
id INTEGER PRIMARY KEY AUTOINCREMENT, |
|||
parent_id INTEGER, |
|||
name TEXT NOT NULL, |
|||
code TEXT, |
|||
value TEXT |
|||
); |
@ -0,0 +1,15 @@ |
|||
package com.qyft.ms; |
|||
|
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan; |
|||
|
|||
@SpringBootApplication |
|||
@ConfigurationPropertiesScan |
|||
public class MatrixSprayApplication { |
|||
|
|||
public static void main(String[] args) { |
|||
SpringApplication.run(MatrixSprayApplication.class, args); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,117 @@ |
|||
package com.qyft.ms.common.constant; |
|||
|
|||
/** |
|||
* 操作指令 |
|||
*/ |
|||
public class Commands { |
|||
/** |
|||
* 抬起托盘 |
|||
*/ |
|||
public static final String UP_TRAY = "upTray"; |
|||
|
|||
/** |
|||
* 降下托盘 |
|||
*/ |
|||
public static final String DOWN_TRAY = "downTray"; |
|||
|
|||
/** |
|||
* 添加溶液 |
|||
*/ |
|||
public static final String INJECT_FLUID = "injectFluid"; |
|||
|
|||
/** |
|||
* 恒温 |
|||
*/ |
|||
public static final String KEEP_HEAT = "keepHeat"; |
|||
|
|||
/** |
|||
* 移至加液 |
|||
*/ |
|||
public static final String MOVE_TO_ACTION_AREA = "moveToActionArea"; |
|||
|
|||
/** |
|||
* 检查加液位状态(是否被占用) |
|||
*/ |
|||
public static final String CHECK_ACTION_AREA = "checkActionArea"; |
|||
|
|||
/** |
|||
* 摇匀试管架 |
|||
*/ |
|||
public static final String START_SHAKE_UP = "startShakeUp"; |
|||
|
|||
/** |
|||
* 停止摇匀试管架 |
|||
*/ |
|||
public static final String STOP_SHAKE_UP = "stopShakeUp"; |
|||
|
|||
/** |
|||
* 开始加热 |
|||
*/ |
|||
public static final String START_HEAT = "startHeat"; |
|||
|
|||
/** |
|||
* 停止加热 |
|||
*/ |
|||
public static final String STOP_HEAT = "stopHeat"; |
|||
|
|||
/** |
|||
* 拍照 |
|||
*/ |
|||
public static final String TAKE_PHOTO = "takePhoto"; |
|||
|
|||
/** |
|||
* 移至异常区 |
|||
*/ |
|||
public static final String MOVE_TO_UNUSUAL = "moveToUnusual"; |
|||
|
|||
/** |
|||
* 从异常区移回加热区 |
|||
*/ |
|||
public static final String MOVE_TO_HEAT_AREA = "moveToHeatArea"; |
|||
|
|||
/** |
|||
* 取试管架盖 |
|||
*/ |
|||
public static final String TAKE_OFF_CAP = "takeOffCap"; |
|||
|
|||
/** |
|||
* 装回试管架盖 |
|||
*/ |
|||
public static final String PUT_BACK_CAP = "putBackCap"; |
|||
|
|||
/** |
|||
* 机械臂移动至指定坐标(x, y, z) |
|||
*/ |
|||
public static final String MOVE_MACHINE_ARM = "moveMachineArm"; |
|||
|
|||
/** |
|||
* 获取当前某种溶液的数量 |
|||
*/ |
|||
public static final String GET_LIQUID_AMOUNT = "getLiquidAmount"; |
|||
|
|||
/** |
|||
* 移动单个试管 |
|||
*/ |
|||
public static final String MOVE_TUBE = "moveTube"; |
|||
|
|||
/** |
|||
* 机械臂爪子开启 |
|||
*/ |
|||
public static final String OPEN_CLAW = "openClaw"; |
|||
|
|||
/** |
|||
* 机械臂爪子闭合 |
|||
*/ |
|||
public static final String CLOSE_CLAW = "closeClaw"; |
|||
|
|||
/** |
|||
* 开门 |
|||
*/ |
|||
public static final String OPEN_DOOR = "openDoor"; |
|||
|
|||
/** |
|||
* 关门 |
|||
*/ |
|||
public static final String CLOSE_DOOR = "closeDoor"; |
|||
|
|||
} |
@ -0,0 +1,27 @@ |
|||
package com.qyft.ms.common.constant; |
|||
|
|||
/** |
|||
* 操作指令 |
|||
*/ |
|||
public class SysSettings { |
|||
/** |
|||
* 加热区域 |
|||
*/ |
|||
public static final String HEAT_AREA = "heat_area"; |
|||
|
|||
/** |
|||
* 加液区域 |
|||
*/ |
|||
public static final String SOLUTION_AREA = "solution_area"; |
|||
|
|||
/** |
|||
* 拍子区域 |
|||
*/ |
|||
public static final String LID_AREA = "lid_area"; |
|||
|
|||
/** |
|||
* 其他系统配置 |
|||
*/ |
|||
public static final String SYS_SETTING = "sys_setting"; |
|||
|
|||
} |
@ -0,0 +1,25 @@ |
|||
package com.qyft.ms.common.constant; |
|||
|
|||
public class WebSocketMessageType { |
|||
/** |
|||
* 设备状态 |
|||
*/ |
|||
public static final String STATUS = "status"; |
|||
/** |
|||
* 设备报警 |
|||
*/ |
|||
public static final String ALARM = "alarm"; |
|||
/** |
|||
* 设备指令反馈 |
|||
*/ |
|||
public static final String CMD = "cmd"; |
|||
/** |
|||
* 工艺执行反馈 |
|||
*/ |
|||
public static final String CRAFTS = "crafts"; |
|||
/** |
|||
* 容器剩余状态 |
|||
*/ |
|||
public static final String CONTAINER = "container"; |
|||
|
|||
} |
@ -0,0 +1,27 @@ |
|||
package com.qyft.ms.common.result; |
|||
|
|||
import com.qyft.ms.system.common.result.IResultCode; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
@AllArgsConstructor |
|||
@NoArgsConstructor |
|||
public enum CMDResultCode implements IResultCode, Serializable { |
|||
SUCCESS("D0000", "执行完毕"), |
|||
FAILURE("D1111", "执行失败"); |
|||
|
|||
private String code; |
|||
private String msg; |
|||
|
|||
@Override |
|||
public String getCode() { |
|||
return code; |
|||
} |
|||
|
|||
@Override |
|||
public String getMsg() { |
|||
return msg; |
|||
} |
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.qyft.ms.config; |
|||
|
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.web.socket.server.standard.ServerEndpointExporter; |
|||
|
|||
@Configuration |
|||
public class WebSocketConfig { |
|||
|
|||
@Bean |
|||
public ServerEndpointExporter serverEndpointExporter() { |
|||
return new ServerEndpointExporter(); |
|||
} |
|||
} |
@ -0,0 +1,59 @@ |
|||
package com.qyft.ms.config; |
|||
|
|||
|
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import com.qyft.ms.model.dto.WebsocketDTO; |
|||
import jakarta.websocket.*; |
|||
import jakarta.websocket.server.ServerEndpoint; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.HashSet; |
|||
import java.util.Set; |
|||
|
|||
@Slf4j |
|||
@ServerEndpoint("/ws") |
|||
@Component |
|||
public class WebSocketServer { |
|||
|
|||
private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<>()); |
|||
|
|||
public static void sendMessageToClients(String message) { |
|||
synchronized (sessions) { |
|||
for (Session session : sessions) { |
|||
try { |
|||
session.getBasicRemote().sendText(message); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@OnOpen |
|||
public void onOpen(Session session) { |
|||
sessions.add(session); |
|||
} |
|||
|
|||
@OnMessage |
|||
public void onMessage(String message, Session session) { |
|||
ObjectMapper objectMapper = new ObjectMapper(); |
|||
try { |
|||
WebsocketDTO c = objectMapper.readValue(message, WebsocketDTO.class); |
|||
log.info("解析后的信息: commandName={}, commandId={}", c.getCommandName(), c.getCommandId()); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
@OnClose |
|||
public void onClose(Session session) { |
|||
sessions.remove(session); // 移除关闭连接的 Session |
|||
} |
|||
|
|||
@OnError |
|||
public void onError(Throwable error) { |
|||
} |
|||
} |
@ -0,0 +1,47 @@ |
|||
package com.qyft.ms.controller; |
|||
|
|||
import cn.hutool.json.JSONUtil; |
|||
import com.qyft.ms.model.form.CMDForm; |
|||
import com.qyft.ms.service.CMDService; |
|||
import com.qyft.ms.system.common.result.Result; |
|||
import io.swagger.v3.oas.annotations.Operation; |
|||
import io.swagger.v3.oas.annotations.tags.Tag; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.util.*; |
|||
|
|||
@Tag(name = "控制指令") |
|||
@RestController |
|||
@RequestMapping("/api/cmd") |
|||
@RequiredArgsConstructor |
|||
@Slf4j |
|||
public class CMDController { |
|||
|
|||
private final CMDService cmdService; |
|||
|
|||
@Operation(summary = "执行指令") |
|||
@PostMapping("/execute") |
|||
public Result<String> execute(@RequestBody CMDForm cmdForm) { |
|||
try { |
|||
String commandId = UUID.randomUUID().toString(); |
|||
if (cmdForm.getCommandId() == null || cmdForm.getCommandId().isEmpty()) { |
|||
cmdForm.setCommandId(commandId); |
|||
} |
|||
log.info("接收到指令: {}", JSONUtil.toJsonStr(cmdForm)); |
|||
if (cmdService.executeCommand(cmdForm)) { |
|||
return Result.success(cmdForm.getCommandId()); |
|||
} else { |
|||
return Result.failed("无效命令"); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e); |
|||
return Result.failed("执行失败"); |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,55 @@ |
|||
package com.qyft.ms.controller; |
|||
|
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.qyft.ms.model.entity.Logs; |
|||
import com.qyft.ms.service.ILogsService; |
|||
import com.qyft.ms.system.common.base.BasePageQuery; |
|||
import com.qyft.ms.system.common.result.PageResult; |
|||
import com.qyft.ms.system.common.result.Result; |
|||
import io.swagger.v3.oas.annotations.Operation; |
|||
import io.swagger.v3.oas.annotations.Parameter; |
|||
import io.swagger.v3.oas.annotations.tags.Tag; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Tag(name = "日志") |
|||
@RestController |
|||
@RequestMapping("/api/logs") |
|||
@RequiredArgsConstructor |
|||
@Slf4j |
|||
public class LogsController { |
|||
private final ILogsService logsService; |
|||
|
|||
@Operation(summary = "日志列表") |
|||
@GetMapping("/list") |
|||
public PageResult<Logs> getAllTasks(BasePageQuery pageQuery) { |
|||
|
|||
return PageResult.success(logsService.page(new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()))); |
|||
} |
|||
|
|||
@Operation(summary = "日志新增") |
|||
@PostMapping("/add") |
|||
public Result<Integer> add(String log) { |
|||
return Result.success(logsService.insertLog(log)); |
|||
} |
|||
|
|||
@Operation(summary = "日志详情") |
|||
@GetMapping("/") |
|||
public Result<Logs> detail(@RequestParam Long id) { |
|||
return Result.success(logsService.getBaseMapper().selectById(id)); |
|||
} |
|||
|
|||
@Operation(summary = "删除日志") |
|||
@DeleteMapping("/{ids}") |
|||
public Result<Boolean> deleteLog(@Parameter(description = "日志ID,多个以英文逗号(,)分割") @PathVariable String ids) { |
|||
List<Long> idsArr = Arrays.stream(ids.split(",")) |
|||
.map(Long::parseLong) |
|||
.collect(Collectors.toList()); |
|||
return Result.success(logsService.removeByIds(idsArr)); |
|||
} |
|||
} |
@ -0,0 +1,56 @@ |
|||
package com.qyft.ms.controller; |
|||
|
|||
import com.qyft.ms.model.dto.SysSettingsDTO; |
|||
import com.qyft.ms.service.ISysSettingsService; |
|||
import com.qyft.ms.system.common.result.Result; |
|||
import io.micrometer.common.lang.Nullable; |
|||
import io.swagger.v3.oas.annotations.Operation; |
|||
import io.swagger.v3.oas.annotations.Parameter; |
|||
import io.swagger.v3.oas.annotations.tags.Tag; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Tag(name = "系统配置") |
|||
@RestController |
|||
@RequestMapping("/api/sys") |
|||
@RequiredArgsConstructor |
|||
@Slf4j |
|||
public class SysSettingsController { |
|||
private final ISysSettingsService sysSettingsService; |
|||
|
|||
@Operation(summary = "获取配置") |
|||
@GetMapping("/getConfig") |
|||
public Result<List<?>> getConfig( |
|||
@Parameter( |
|||
description = "配置类型(heat_area 工作区配置 solution_area 加液区配置 lid_area 拍子区域配置 sys_setting 其他系统配置)" |
|||
) |
|||
@RequestParam |
|||
@Nullable |
|||
String type |
|||
) { |
|||
if (type == null) { |
|||
return Result.success(sysSettingsService.getAllConfig()); |
|||
} else { |
|||
return Result.success(sysSettingsService.getConfig(type)); |
|||
} |
|||
} |
|||
|
|||
@Operation(summary = "更新配置") |
|||
@PutMapping("/updateConfig") |
|||
public Result<String> updateConfig(@RequestBody List<SysSettingsDTO> dto) { |
|||
return Result.failed(); |
|||
} |
|||
|
|||
@Operation(summary = "修改系统日期与时间(Linux date -s)") |
|||
@PutMapping("/setSysDate/{newTime}") |
|||
public Result<String> setSysDate(@Parameter(description = "时间字符串 YYYY-MM-DD HH:mm:ss") @PathVariable String newTime) { |
|||
boolean isSuccess = sysSettingsService.setSysDate(newTime); |
|||
if (isSuccess) { |
|||
return Result.success(); |
|||
} |
|||
return Result.failed(); |
|||
} |
|||
} |
@ -0,0 +1,160 @@ |
|||
package com.qyft.ms.device.client; |
|||
|
|||
import cn.hutool.json.JSONUtil; |
|||
import com.qyft.ms.device.common.jsonrpc.JsonRpcRequest; |
|||
import com.qyft.ms.device.config.TcpConfig; |
|||
import com.qyft.ms.device.handler.DeviceMessageHandler; |
|||
import com.qyft.ms.device.model.bo.DeviceFeedback; |
|||
import io.netty.bootstrap.Bootstrap; |
|||
import io.netty.buffer.Unpooled; |
|||
import io.netty.channel.*; |
|||
import io.netty.channel.nio.NioEventLoopGroup; |
|||
import io.netty.channel.socket.nio.NioSocketChannel; |
|||
import io.netty.handler.codec.json.JsonObjectDecoder; |
|||
import io.netty.util.CharsetUtil; |
|||
import jakarta.annotation.PostConstruct; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.net.InetSocketAddress; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.CompletableFuture; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Slf4j |
|||
@Component |
|||
@RequiredArgsConstructor |
|||
public class TcpClient { |
|||
|
|||
private final TcpConfig tcpConfig; |
|||
|
|||
private final DeviceMessageHandler deviceMessageHandler; |
|||
|
|||
private final EventLoopGroup group = new NioEventLoopGroup(); |
|||
private Channel channel; |
|||
private Bootstrap bootstrap; |
|||
|
|||
|
|||
@PostConstruct |
|||
public void init() { |
|||
if (tcpConfig.isEnable()) { |
|||
connect(); |
|||
} |
|||
} |
|||
|
|||
public void connect() { |
|||
try { |
|||
if (bootstrap == null) { |
|||
bootstrap = new Bootstrap(); |
|||
bootstrap.group(group) |
|||
.channel(NioSocketChannel.class) |
|||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, tcpConfig.getTimeout()) |
|||
.handler(new ChannelInitializer<>() { |
|||
@Override |
|||
protected void initChannel(Channel ch) { |
|||
ch.pipeline().addLast(new JsonObjectDecoder()); |
|||
ch.pipeline().addLast(deviceMessageHandler); |
|||
ch.pipeline().addLast(new TcpConnectionHandler()); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
log.info("尝试连接到TCP服务 {}:{}", tcpConfig.getHost(), tcpConfig.getPort()); |
|||
ChannelFuture future = bootstrap.connect(new InetSocketAddress(tcpConfig.getHost(), tcpConfig.getPort())); |
|||
|
|||
future.addListener((ChannelFutureListener) f -> { |
|||
if (f.isSuccess()) { |
|||
channel = f.channel(); |
|||
log.info("已链接到TCP服务"); |
|||
} else { |
|||
log.error("无法连接到TCP服务. {}ms后重试...", tcpConfig.getReconnect()); |
|||
f.channel().eventLoop().schedule(this::connect, tcpConfig.getReconnect(), TimeUnit.MILLISECONDS); |
|||
} |
|||
}); |
|||
|
|||
} catch (Exception e) { |
|||
log.error("尝试连接到TCP服务发生意外错误: {}", e.getMessage(), e); |
|||
} |
|||
} |
|||
|
|||
@Scheduled(fixedRateString = "${tcp.reconnect}") |
|||
public void checkConnection() { |
|||
if (channel == null || !channel.isActive()) { |
|||
log.error("TCP服务链接丢失"); |
|||
connect(); |
|||
} |
|||
} |
|||
|
|||
public boolean send(String request) { |
|||
if (channel != null && channel.isActive()) { |
|||
channel.writeAndFlush(Unpooled.copiedBuffer(request, CharsetUtil.UTF_8)); |
|||
return true; |
|||
} else { |
|||
log.error("TCP服务未连接,无法发送请求: {}", request); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
public DeviceFeedback sendCommand(String method) { |
|||
JsonRpcRequest request = new JsonRpcRequest(); |
|||
request.setMethod(method); |
|||
return this.sendCommand(request); |
|||
} |
|||
|
|||
public DeviceFeedback sendCommand(String method, Map<String, Object> params) { |
|||
JsonRpcRequest request = new JsonRpcRequest(); |
|||
request.setMethod(method); |
|||
request.setParams(params); |
|||
return this.sendCommand(request); |
|||
} |
|||
|
|||
public DeviceFeedback sendCommand(JsonRpcRequest request) { |
|||
if (request.getId() == null) { |
|||
request.setId(UUID.randomUUID().toString()); |
|||
} |
|||
CompletableFuture<DeviceFeedback> future = new CompletableFuture<>(); |
|||
deviceMessageHandler.responseMap.put(request.getId(), future); |
|||
try { |
|||
if (request.getParams() == null) { |
|||
request.setParams(new HashMap<>()); |
|||
} |
|||
request.getParams().put("class", "test"); |
|||
String requestJsonStr = JSONUtil.toJsonStr(request); |
|||
log.info("发送TCP指令(同步) {}", requestJsonStr); |
|||
if (this.send(requestJsonStr)) { |
|||
return future.get(tcpConfig.getFeedbackTimeout(), TimeUnit.MILLISECONDS); // 等待 FEEDBACK 响应 |
|||
} else { |
|||
return null; |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("发送TCP指令错误(同步) {}", JSONUtil.toJsonStr(request), e); |
|||
} finally { |
|||
deviceMessageHandler.responseMap.remove(request.getId()); //确保完成后移除 |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
private class TcpConnectionHandler extends ChannelInboundHandlerAdapter { |
|||
|
|||
@Override |
|||
public void channelInactive(ChannelHandlerContext ctx) throws Exception { |
|||
// 连接断开时的处理逻辑 |
|||
log.error("TCP连接丢失,准备重新连接..."); |
|||
if (channel != null) { |
|||
channel.close(); |
|||
} |
|||
connect(); |
|||
super.channelInactive(ctx); |
|||
} |
|||
|
|||
@Override |
|||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { |
|||
log.error("TCP连接发生异常: {}", cause.getMessage(), cause); |
|||
ctx.close(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,38 @@ |
|||
package com.qyft.ms.device.common.constant; |
|||
|
|||
public class DeviceCommands { |
|||
|
|||
/** |
|||
* 使指定轴的电机回原点 |
|||
*/ |
|||
public static final String MOTOR_MOVE_TO_HOME = "motorMoveToHome"; |
|||
// 设置指定轴的电机的运行电流 |
|||
public static final String SET_MOTOR_RUNNING_CURRENT = "setMotorRunningCurrent"; |
|||
// 移动指定轴的电机到指定位置 |
|||
public static final String MOVE_MOTOR_TO_POSITION = "moveMotorToPosition"; |
|||
// 设置指定轴的电机的运行速度 |
|||
public static final String SET_MOTOR_SPEED = "setMotorSpeed"; |
|||
// 切换三通阀到基质状态 |
|||
public static final String SWITCH_THREE_WAY_VALVE_TO_SUBSTRATE = "switchThreeWayValveToSubstrate"; |
|||
// 切换三通阀到喷涂状态 |
|||
public static final String SWITCH_THREE_WAY_VALVE_TO_SPRAY = "switchThreeWayValveToSpray"; |
|||
// 控制指定阀的开启或关闭 |
|||
public static final String CONTROL_VALVE = "controlValve"; |
|||
// 以指定亮度开启照明灯板 |
|||
public static final String TURN_ON_LIGHT_PANEL = "turnOnLightPanel"; |
|||
// 关闭照明灯板 |
|||
public static final String TURN_OFF_LIGHT_PANEL = "turnOffLightPanel"; |
|||
// 以指定电压值开启高压电 |
|||
public static final String TURN_ON_HIGH_VOLTAGE = "turnOnHighVoltage"; |
|||
// 关闭高压电 |
|||
public static final String TURN_OFF_HIGH_VOLTAGE = "turnOffHighVoltage"; |
|||
// 以指定转速、方向和时间开启注射泵 |
|||
public static final String TURN_ON_SYRINGE_PUMP = "turnOnSyringePump"; |
|||
// 停止注射泵 |
|||
public static final String TURN_OFF_SYRINGE_PUMP = "turnOffSyringePump"; |
|||
// 设置注射泵的容量、时间比例参数 |
|||
public static final String SET_SYRINGE_PUMP_PARAMETERS = "setSyringePumpParameters"; |
|||
// 推送指定容量的液体 |
|||
public static final String PUSH_VOLUME = "pushVolume"; |
|||
|
|||
} |
@ -0,0 +1,16 @@ |
|||
package com.qyft.ms.device.common.constant; |
|||
|
|||
public class TcpMessageType { |
|||
/** |
|||
* 设备状态 |
|||
*/ |
|||
public static final String STATUS = "status"; |
|||
/** |
|||
* 设备报警 |
|||
*/ |
|||
public static final String ALARM = "alarm"; |
|||
/** |
|||
* 设备指令反馈 |
|||
*/ |
|||
public static final String FEEDBACK = "feedback"; |
|||
} |
@ -0,0 +1,24 @@ |
|||
package com.qyft.ms.device.common.jsonrpc; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* TCP JSON RPC请求 |
|||
*/ |
|||
@Data |
|||
public class JsonRpcRequest { |
|||
/** |
|||
* 请求id |
|||
*/ |
|||
private String id; |
|||
/** |
|||
* 请求方法 |
|||
*/ |
|||
private String method; |
|||
/** |
|||
* 请求参数 |
|||
*/ |
|||
private Map<String, Object> params; |
|||
} |
@ -0,0 +1,16 @@ |
|||
package com.qyft.ms.device.common.jsonrpc; |
|||
|
|||
import cn.hutool.json.JSONObject; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class JsonRpcResponse { |
|||
/** |
|||
* 数据类型 |
|||
*/ |
|||
private String type; |
|||
/** |
|||
* 数据 |
|||
*/ |
|||
private JSONObject data; |
|||
} |
@ -0,0 +1,37 @@ |
|||
package com.qyft.ms.device.config; |
|||
|
|||
import lombok.Data; |
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
@Data |
|||
@Component |
|||
@ConfigurationProperties(prefix = "tcp") |
|||
public class TcpConfig { |
|||
/** |
|||
* 是否启用 TCP 连接 |
|||
*/ |
|||
private boolean enable; |
|||
/** |
|||
* TCP 链接地址 |
|||
*/ |
|||
private String host; |
|||
/** |
|||
* TCP 端口 |
|||
*/ |
|||
private int port; |
|||
/** |
|||
* 断线重连间隔(毫秒) |
|||
*/ |
|||
private int reconnect; |
|||
/** |
|||
* 连接超时时间(毫秒) |
|||
*/ |
|||
private int timeout; |
|||
/** |
|||
* 指令反馈超时时间 |
|||
*/ |
|||
private int feedbackTimeout; |
|||
|
|||
} |
|||
|
@ -0,0 +1,37 @@ |
|||
package com.qyft.ms.device.controller; |
|||
|
|||
import com.qyft.ms.device.model.bo.DeviceOperationalStatus; |
|||
import com.qyft.ms.device.model.bo.DeviceStatus; |
|||
import com.qyft.ms.device.service.DeviceStatusService; |
|||
import com.qyft.ms.system.common.result.Result; |
|||
import io.swagger.v3.oas.annotations.Operation; |
|||
import io.swagger.v3.oas.annotations.tags.Tag; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
@Tag(name = "设备控制") |
|||
@RestController |
|||
@RequestMapping("/api/device") |
|||
@RequiredArgsConstructor |
|||
@Slf4j |
|||
public class DeviceController { |
|||
private final DeviceStatusService deviceStatusService; |
|||
|
|||
@Operation(summary = "获取设备业务操作状态") |
|||
@GetMapping("/operational/status") |
|||
public Result<DeviceOperationalStatus> getDeviceOperationalStatus() { |
|||
DeviceOperationalStatus deviceOperationalStatus = deviceStatusService.getDeviceOperationalStatus(); |
|||
return Result.success(deviceOperationalStatus); |
|||
} |
|||
|
|||
|
|||
@Operation(summary = "获取当前设备状态") |
|||
@GetMapping("/status") |
|||
public Result<DeviceStatus> getDeviceStatus() { |
|||
DeviceStatus deviceStatus = deviceStatusService.getDeviceStatus(); |
|||
return Result.success(deviceStatus); |
|||
} |
|||
} |
@ -0,0 +1,93 @@ |
|||
package com.qyft.ms.device.controller; |
|||
|
|||
import com.qyft.ms.device.model.bo.DeviceCtrlFuncCMD; |
|||
import com.qyft.ms.device.model.entity.CtrlFunc; |
|||
import com.qyft.ms.device.model.form.CtrlFuncForm; |
|||
import com.qyft.ms.device.model.vo.DeviceCtrlFuncVO; |
|||
import com.qyft.ms.device.service.ICtrlFuncService; |
|||
import com.qyft.ms.system.common.result.Result; |
|||
import com.qyft.ms.system.common.result.ResultCode; |
|||
import io.swagger.v3.oas.annotations.Operation; |
|||
import io.swagger.v3.oas.annotations.Parameter; |
|||
import io.swagger.v3.oas.annotations.tags.Tag; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Tag(name = "设备控制") |
|||
@RestController |
|||
@RequestMapping("/api/device") |
|||
@RequiredArgsConstructor |
|||
@Slf4j |
|||
public class DeviceCtrlController { |
|||
private final ICtrlFuncService ctrlFuncService; |
|||
|
|||
@Operation(summary = "获取所有设备控制方法步骤") |
|||
@GetMapping("/ctrl/step") |
|||
public Result<List<DeviceCtrlFuncCMD>> getAllCtrlFuncStep() { |
|||
List<DeviceCtrlFuncCMD> ctrlFuncList = ctrlFuncService.findAllStepCMD(); |
|||
return Result.success(ctrlFuncList); |
|||
} |
|||
|
|||
@Operation(summary = "获取所有设备控制方法") |
|||
@GetMapping("/ctrl") |
|||
public Result<List<CtrlFunc>> getAllCtrlFunc() { |
|||
List<CtrlFunc> ctrlFuncList = ctrlFuncService.findAll(); |
|||
return Result.success(ctrlFuncList); |
|||
} |
|||
|
|||
@Operation(summary = "根据id获取设备控制方法与步骤") |
|||
@GetMapping("/ctrl/{id}") |
|||
public Result<DeviceCtrlFuncVO> getById(@PathVariable Long id) { |
|||
DeviceCtrlFuncVO ctrlFuncVO = ctrlFuncService.findVOById(id); |
|||
return Result.success(ctrlFuncVO); |
|||
} |
|||
|
|||
@Operation(summary = "添加设备控制方法与步骤") |
|||
@PostMapping("/ctrl") |
|||
public Result<String> addCtrlFunc(@RequestBody CtrlFuncForm ctrlFuncForm) { |
|||
long count = ctrlFuncService.countFuncCmdByFuncCmd(ctrlFuncForm.getFuncCmd()); |
|||
if (count > 0) { |
|||
return Result.failed(ResultCode.DATA_ALREADY_EXISTS); |
|||
|
|||
} |
|||
boolean isSuccess = ctrlFuncService.addCtrlFunc(ctrlFuncForm); |
|||
if (isSuccess) { |
|||
return Result.success(); |
|||
} |
|||
return Result.failed(); |
|||
} |
|||
|
|||
@Operation(summary = "更新设备控制方法与步骤") |
|||
@PutMapping("/ctrl/{id}") |
|||
public Result<String> updateCtrlFunc(@PathVariable Long id, @RequestBody CtrlFuncForm ctrlFuncForm) { |
|||
CtrlFunc currentCtrlFunc = ctrlFuncService.getById(id); |
|||
if (currentCtrlFunc != null && !currentCtrlFunc.getFuncCmd().equals(ctrlFuncForm.getFuncCmd())) { |
|||
//改了指令需要判断指令是否重复 |
|||
long count = ctrlFuncService.countFuncCmdByFuncCmd(ctrlFuncForm.getFuncCmd()); |
|||
if (count > 0) { |
|||
return Result.failed(ResultCode.DATA_ALREADY_EXISTS); |
|||
} |
|||
} |
|||
boolean isSuccess = ctrlFuncService.updateCtrlFunc(id, ctrlFuncForm); |
|||
if (isSuccess) { |
|||
return Result.success(); |
|||
} |
|||
|
|||
return Result.failed(); |
|||
} |
|||
|
|||
@Operation(summary = "删除设备控制方法") |
|||
@DeleteMapping("/ctrl/{ids}") |
|||
public Result<String> deleteCtrlFunc(@Parameter(description = "设备控制方法ID,多个以英文逗号(,)分割") @PathVariable String ids) { |
|||
boolean isSuccess = ctrlFuncService.deleteCtrlFunc(ids); |
|||
if (isSuccess) { |
|||
return Result.success(); |
|||
} |
|||
return Result.failed(); |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,43 @@ |
|||
package com.qyft.ms.device.controller; |
|||
|
|||
import com.qyft.ms.device.model.bo.DeviceStatus; |
|||
import com.qyft.ms.device.service.DeviceTcpCMDService; |
|||
import com.qyft.ms.device.service.DeviceStatusService; |
|||
import com.qyft.ms.system.common.result.Result; |
|||
import io.swagger.v3.oas.annotations.Operation; |
|||
import io.swagger.v3.oas.annotations.tags.Tag; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
@Tag(name = "测试") |
|||
@RestController |
|||
@RequestMapping("/api/test") |
|||
@RequiredArgsConstructor |
|||
@Slf4j |
|||
public class TestController { |
|||
private final DeviceTcpCMDService deviceTcpCMDService; |
|||
private final DeviceStatusService deviceStatusService; |
|||
|
|||
@Operation(summary = "生成设备状态实体") |
|||
@GetMapping("/getDeviceStatus") |
|||
public Result<DeviceStatus> getDeviceStatus() { |
|||
DeviceStatus deviceStatus = deviceStatusService.getDeviceStatus(); |
|||
return Result.success(deviceStatus); |
|||
} |
|||
|
|||
@Operation(summary = "触发测试报警") |
|||
@GetMapping("/alarmTest") |
|||
public Result<DeviceStatus> alarmTest(@RequestParam String code, @RequestParam String msg, @RequestParam String module) { |
|||
boolean success = deviceTcpCMDService.alarmTest(code, msg, module); |
|||
if (success) { |
|||
return Result.success(); |
|||
} else { |
|||
return Result.failed("触发测试报警失败"); |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,68 @@ |
|||
package com.qyft.ms.device.handler; |
|||
|
|||
import cn.hutool.json.JSONUtil; |
|||
import com.qyft.ms.common.constant.WebSocketMessageType; |
|||
import com.qyft.ms.device.common.constant.TcpMessageType; |
|||
import com.qyft.ms.device.common.jsonrpc.JsonRpcResponse; |
|||
import com.qyft.ms.device.model.bo.DeviceAlarm; |
|||
import com.qyft.ms.device.model.bo.DeviceFeedback; |
|||
import com.qyft.ms.device.model.bo.DeviceStatus; |
|||
import com.qyft.ms.device.service.DeviceStatusService; |
|||
import com.qyft.ms.service.WebSocketService; |
|||
import io.netty.buffer.ByteBuf; |
|||
import io.netty.channel.ChannelHandler; |
|||
import io.netty.channel.ChannelHandlerContext; |
|||
import io.netty.channel.ChannelInboundHandlerAdapter; |
|||
import io.netty.util.CharsetUtil; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.util.Map; |
|||
import java.util.concurrent.CompletableFuture; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
@Slf4j |
|||
@Component |
|||
@ChannelHandler.Sharable |
|||
@RequiredArgsConstructor |
|||
public class DeviceMessageHandler extends ChannelInboundHandlerAdapter { |
|||
|
|||
public final Map<String, CompletableFuture<DeviceFeedback>> responseMap = new ConcurrentHashMap<>(); |
|||
private final DeviceStatusService deviceStatusService; |
|||
private final WebSocketService webSocketService; |
|||
|
|||
@Override |
|||
public void channelRead(ChannelHandlerContext ctx, Object msg) { |
|||
ByteBuf buf = (ByteBuf) msg; |
|||
String serverMsg = buf.toString(CharsetUtil.UTF_8); |
|||
try { |
|||
JsonRpcResponse jsonRpcResponse = JSONUtil.toBean(serverMsg, JsonRpcResponse.class); |
|||
if (TcpMessageType.STATUS.equals(jsonRpcResponse.getType())) {//设备状态 |
|||
DeviceStatus deviceStatus = JSONUtil.toBean(jsonRpcResponse.getData(), DeviceStatus.class); |
|||
deviceStatusService.updateDeviceStatus(deviceStatus); // 更新设备状态 |
|||
} else if (TcpMessageType.ALARM.equals(jsonRpcResponse.getType())) {//设备报警 |
|||
log.error("设备报警: {}", serverMsg); |
|||
DeviceAlarm deviceAlarm = JSONUtil.toBean(jsonRpcResponse.getData(), DeviceAlarm.class); |
|||
webSocketService.pushMsg(WebSocketMessageType.ALARM, deviceAlarm); |
|||
} else if (TcpMessageType.FEEDBACK.equals(jsonRpcResponse.getType())) {//设备指令反馈 |
|||
DeviceFeedback deviceFeedback = JSONUtil.toBean(jsonRpcResponse.getData(), DeviceFeedback.class); |
|||
this.handleTcpResponse(deviceFeedback); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("TCP服务消息处理错误: {}, error: {}", serverMsg, e.getMessage(), e); |
|||
} finally { |
|||
buf.release(); |
|||
} |
|||
} |
|||
|
|||
private void handleTcpResponse(DeviceFeedback deviceFeedback) { |
|||
String requestId = deviceFeedback.getId(); |
|||
CompletableFuture<DeviceFeedback> future = responseMap.remove(requestId); |
|||
if (future != null) { |
|||
future.complete(deviceFeedback); |
|||
} else { |
|||
log.error("未找到 requestId: {} 对应的等待请求", requestId); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,11 @@ |
|||
package com.qyft.ms.device.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.qyft.ms.device.model.entity.CtrlFunc; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
|
|||
@Mapper |
|||
public interface CtrlFuncMapper extends BaseMapper<CtrlFunc> { |
|||
|
|||
} |
|||
|
@ -0,0 +1,11 @@ |
|||
package com.qyft.ms.device.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.qyft.ms.device.model.entity.CtrlFuncStep; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
|
|||
@Mapper |
|||
public interface CtrlFuncStepMapper extends BaseMapper<CtrlFuncStep> { |
|||
|
|||
} |
|||
|
@ -0,0 +1,18 @@ |
|||
package com.qyft.ms.device.model.bo; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* 设备报警信息 |
|||
*/ |
|||
@Schema(description = "设备报警信息") |
|||
@Data |
|||
public class DeviceAlarm { |
|||
@Schema(description = "报警代码") |
|||
private String code; |
|||
@Schema(description = "报警信息") |
|||
private String msg; |
|||
@Schema(description = "报警模块") |
|||
private String module; |
|||
} |
@ -0,0 +1,27 @@ |
|||
package com.qyft.ms.device.model.bo; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Schema(description = "设备控制方法步骤指令") |
|||
@Data |
|||
public class DeviceCtrlFuncCMD { |
|||
|
|||
public DeviceCtrlFuncCMD(String name, String deviceCmd, String params) { |
|||
this.name = name; |
|||
this.deviceCmd = deviceCmd; |
|||
this.params = params; |
|||
} |
|||
|
|||
@Schema(description = "指令名称") |
|||
private String name; |
|||
|
|||
@Schema(description = "设备指令") |
|||
private String deviceCmd; |
|||
|
|||
@Schema(description = "参数") |
|||
private String params; |
|||
|
|||
} |
@ -0,0 +1,26 @@ |
|||
package com.qyft.ms.device.model.bo; |
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* 设备当前状态 |
|||
*/ |
|||
@Data |
|||
public class DeviceFeedback { |
|||
/** |
|||
* 请求id |
|||
*/ |
|||
private String id; |
|||
/** |
|||
* 请求数据 |
|||
*/ |
|||
private Object result; |
|||
|
|||
private DeviceFeedbackError error; |
|||
|
|||
@Data |
|||
static class DeviceFeedbackError { |
|||
private String code; |
|||
private String message; |
|||
} |
|||
} |
@ -0,0 +1,38 @@ |
|||
package com.qyft.ms.device.model.bo; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
@Schema(description = "设备业务操作状态") |
|||
@Data |
|||
public class DeviceOperationalStatus { |
|||
@Schema(description = "托盘列表") |
|||
private List<Tray> trayList = new ArrayList<>(); |
|||
|
|||
/** |
|||
* 托盘 |
|||
*/ |
|||
@Data |
|||
static class Tray { |
|||
@Schema(description = "所在加热区id") |
|||
private Long heatId; |
|||
@Schema(description = "是否在加液区") |
|||
private boolean isSolutionArea; |
|||
@Schema(description = "试管列表") |
|||
private List<Tube> tubeList; |
|||
} |
|||
|
|||
/** |
|||
* 试管 |
|||
*/ |
|||
@Data |
|||
static class Tube { |
|||
@Schema(description = "试管编号") |
|||
private Integer tubeNum; |
|||
@Schema(description = "试管内是否有样品") |
|||
private boolean isSample; |
|||
} |
|||
} |
@ -0,0 +1,140 @@ |
|||
package com.qyft.ms.device.model.bo; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 设备当前状态 |
|||
*/ |
|||
@Schema(description = "设备当前传感器状态") |
|||
@Data |
|||
public class DeviceStatus { |
|||
|
|||
@Schema(description = "是否是急停状态,true为急停") |
|||
private Boolean emergencyStop; |
|||
|
|||
@Schema(description = "门状态,true为开启状态,false为关闭状态") |
|||
private Boolean doorStatus; |
|||
|
|||
@Schema(description = "导轨机械臂状态") |
|||
private RailArm railArm; |
|||
|
|||
@Schema(description = "加液操作区属性") |
|||
private LiquidArea liquidArea; |
|||
|
|||
@Schema(description = "加热操作区属性") |
|||
private List<HeatArea> heatArea; |
|||
|
|||
@Schema(description = "碱容器状态") |
|||
private LiquidBucket alkaliBucket; |
|||
|
|||
|
|||
/** |
|||
* 导轨机械臂属性 |
|||
*/ |
|||
@Data |
|||
public static class RailArm { |
|||
@Schema(description = "当前所在x坐标") |
|||
private Integer x; |
|||
@Schema(description = "当前所在y坐标") |
|||
private Integer y; |
|||
@Schema(description = "当前所在z坐标") |
|||
private Integer z; |
|||
@Schema(description = "当前轴1角度") |
|||
private Double joint1; |
|||
@Schema(description = "当前轴2角度") |
|||
private Double joint2; |
|||
@Schema(description = "当前机械臂(轴3)上下移动距离") |
|||
private Integer distance; |
|||
@Schema(description = "当前导轨移动距离") |
|||
private Double railDistance; |
|||
@Schema(description = "当前夹爪移动距离") |
|||
private Double clawDistance; |
|||
@Schema(description = "夹爪状态,true为张开状态,false为闭合状态") |
|||
private Boolean clawStatus; |
|||
@Schema(description = "导轨是否在原点,true为在原点") |
|||
private Boolean isZeroPos; |
|||
@Schema(description = "导轨是否在限位点,true为在限位点") |
|||
private Boolean isLimitPos; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 加液操作区属性 |
|||
*/ |
|||
@Data |
|||
public static class LiquidArea { |
|||
@Schema(description = "加液机械臂状态") |
|||
private LiquidArm liquidArm; |
|||
|
|||
@Schema(description = "是否正在摇匀,true为正在摇匀,false为停止摇匀") |
|||
private Boolean isShaking; |
|||
|
|||
@Schema(description = "是否存在托盘,true为存在托盘,false为无托盘") |
|||
private Boolean liquidTray; |
|||
|
|||
@Schema(description = "溶液容器状态") |
|||
private List<LiquidBucket> solutionBucket; |
|||
} |
|||
|
|||
/** |
|||
* 加热操作区属性 |
|||
*/ |
|||
@Data |
|||
public static class HeatArea { |
|||
@Schema(description = "加热器设备id") |
|||
private String hardwareId; |
|||
@Schema(description = "托盘状态,0为无托盘,1为有托盘,2为托盘抬起") |
|||
private Integer trayStatus; |
|||
@Schema(description = "是否正在加热,true为正在加热,false为未加热") |
|||
private Boolean isHeating; |
|||
@Schema(description = "拍子状态,true为存在拍子,false无拍子") |
|||
private Boolean capStatus; |
|||
@Schema(description = "拍子密封状态,true为已密封,false为未密封") |
|||
private Boolean isSealed; |
|||
@Schema(description = "加热器当前温度") |
|||
private Double temperature; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 加液机械臂属性 |
|||
*/ |
|||
@Data |
|||
public static class LiquidArm { |
|||
@Schema(description = "当前所在x坐标") |
|||
private Integer x; |
|||
@Schema(description = "当前所在y坐标") |
|||
private Integer y; |
|||
@Schema(description = "当前所在z坐标") |
|||
private Integer z; |
|||
@Schema(description = "当前轴1角度") |
|||
private Double joint1; |
|||
@Schema(description = "当前轴2角度") |
|||
private Double joint2; |
|||
@Schema(description = "加液泵状态") |
|||
private List<Pump> pump; |
|||
} |
|||
|
|||
/** |
|||
* 泵属性 |
|||
*/ |
|||
@Data |
|||
public static class Pump { |
|||
@Schema(description = "加液泵id") |
|||
private String pumpId; |
|||
@Schema(description = "是否正在加液,true正在加液,false未运行") |
|||
private Integer isPumping; |
|||
} |
|||
|
|||
|
|||
@Data |
|||
public static class LiquidBucket { |
|||
@Schema(description = "容器是否为空,true为空,false不为空") |
|||
private Boolean isEmpty; |
|||
@Schema(description = "容器是否为满,true为满,false不满") |
|||
private Boolean isFull; |
|||
} |
|||
} |
@ -0,0 +1,23 @@ |
|||
package com.qyft.ms.device.model.entity; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import com.qyft.ms.system.common.base.BaseEntity; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Schema(description = "设备控制方法记录表") |
|||
@TableName("ctrl_func") |
|||
@Data |
|||
public class CtrlFunc extends BaseEntity { |
|||
@NotBlank |
|||
@Schema(description = "控制方法的名称") |
|||
private String name; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "控制方法的指令") |
|||
private String funcCmd; |
|||
|
|||
} |
@ -0,0 +1,27 @@ |
|||
package com.qyft.ms.device.model.entity; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import com.qyft.ms.system.common.base.BaseEntity; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Schema(description = "设备控制方法步骤表") |
|||
@TableName("ctrl_func_step") |
|||
@Data |
|||
public class CtrlFuncStep extends BaseEntity { |
|||
|
|||
@Schema(description = "控制方法的指令") |
|||
private String funcCmd; |
|||
|
|||
@Schema(description = "设备指令") |
|||
private String deviceCmd; |
|||
|
|||
@Schema(description = "备注说明") |
|||
private String remarks; |
|||
|
|||
@Schema(description = "设备指令的参数,为null则动态传入") |
|||
private String params; |
|||
|
|||
} |
@ -0,0 +1,38 @@ |
|||
package com.qyft.ms.device.model.form; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Schema(description = "设备控制方法表单") |
|||
@Data |
|||
public class CtrlFuncForm { |
|||
|
|||
@Schema(description = "控制方法的名称") |
|||
private String name; |
|||
|
|||
@Schema(description = "控制方法的指令") |
|||
private String funcCmd; |
|||
|
|||
@Schema(description = "设备控制方法步骤") |
|||
private List<CtrlFuncStepForm> ctrlFuncStepList; |
|||
|
|||
@Data |
|||
public static class CtrlFuncStepForm { |
|||
|
|||
@Schema(description = "设备指令") |
|||
private String deviceCmd; |
|||
|
|||
@Schema(description = "备注说明") |
|||
private String remarks; |
|||
|
|||
@Schema(description = "设备指令的参数,为null则动态传入") |
|||
private Map<String, Object> params; |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,26 @@ |
|||
package com.qyft.ms.device.model.vo; |
|||
|
|||
import com.qyft.ms.device.model.entity.CtrlFuncStep; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.util.List; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Schema(description = "获取所有设备控制方法返回数据") |
|||
@Data |
|||
public class CtrlFuncVO { |
|||
|
|||
private Long id; |
|||
|
|||
@Schema(description = "控制方法的名称") |
|||
private String name; |
|||
|
|||
@Schema(description = "控制方法的指令") |
|||
private String funcCmd; |
|||
|
|||
@Schema(description = "设备控制方法步骤列表") |
|||
private List<CtrlFuncStep> ctrlFuncStepList; |
|||
|
|||
} |
@ -0,0 +1,26 @@ |
|||
package com.qyft.ms.device.model.vo; |
|||
|
|||
import com.qyft.ms.device.model.entity.CtrlFuncStep; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.util.List; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Schema(description = "获取所有设备控制方法返回数据") |
|||
@Data |
|||
public class DeviceCtrlFuncVO { |
|||
|
|||
private Long id; |
|||
|
|||
@Schema(description = "控制方法的名称") |
|||
private String name; |
|||
|
|||
@Schema(description = "控制方法的指令") |
|||
private String funcCmd; |
|||
|
|||
@Schema(description = "设备控制方法步骤列表") |
|||
private List<CtrlFuncStep> ctrlFuncStepList; |
|||
|
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.qyft.ms.device.service; |
|||
|
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
/** |
|||
* 设备报警服务 |
|||
*/ |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class DeviceAlarmService { |
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.qyft.ms.device.service; |
|||
|
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
/** |
|||
* 设备操作 |
|||
*/ |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class DeviceService { |
|||
|
|||
|
|||
} |
@ -0,0 +1,47 @@ |
|||
package com.qyft.ms.device.service; |
|||
|
|||
import cn.hutool.core.bean.BeanUtil; |
|||
import com.qyft.ms.device.model.bo.DeviceOperationalStatus; |
|||
import com.qyft.ms.device.model.bo.DeviceStatus; |
|||
import lombok.Getter; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
/** |
|||
* 设备传感器状态推送 |
|||
*/ |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class DeviceStatusService { |
|||
/** |
|||
* 设备运行状态 |
|||
*/ |
|||
private final DeviceStatus deviceStatus = new DeviceStatus(); |
|||
/** |
|||
* 设备业务状态 |
|||
* -- GETTER -- |
|||
* 更新设备业务操作状态 |
|||
*/ |
|||
@Getter |
|||
private final DeviceOperationalStatus deviceOperationalStatus = new DeviceOperationalStatus(); |
|||
|
|||
/** |
|||
* 更新设备状态 |
|||
*/ |
|||
public void updateDeviceStatus(DeviceStatus newStatus) { |
|||
synchronized (deviceStatus) { |
|||
BeanUtil.copyProperties(newStatus, deviceStatus); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取设备状态 |
|||
*/ |
|||
public DeviceStatus getDeviceStatus() { |
|||
synchronized (deviceStatus) { |
|||
return BeanUtil.copyProperties(deviceStatus, DeviceStatus.class); |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,166 @@ |
|||
package com.qyft.ms.device.service; |
|||
|
|||
import com.qyft.ms.model.bo.TubeSol; |
|||
import com.qyft.ms.service.CMDService; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 设备步骤操作 |
|||
*/ |
|||
@Slf4j |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class DeviceStepService { |
|||
|
|||
CMDService cmdService; |
|||
|
|||
/** |
|||
* 抬起托盘 |
|||
* |
|||
* @param heatId 加热区id |
|||
*/ |
|||
public boolean upTray(String heatId) { |
|||
// Map<String, Object> params = Map.of("heatId", heatId); |
|||
// List<Supplier<Boolean>> cmdList = cmdService.upTray(params); |
|||
// return cmdList.stream().allMatch(Supplier::get); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 降下托盘 |
|||
* |
|||
* @param heatId 加热区id |
|||
*/ |
|||
public boolean downTray(String heatId) { |
|||
// Map<String, Object> params = Map.of("heatId", heatId); |
|||
// List<Supplier<Boolean>> cmdList = cmdService.downTray(params); |
|||
// return cmdList.stream().allMatch(Supplier::get); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 添加溶液 |
|||
* |
|||
* @param tubeSolList 需要添加溶液的试管与溶液 |
|||
*/ |
|||
public boolean addLiquid(List<TubeSol> tubeSolList) { |
|||
// for (TubeSol tubeSol : tubeSolList) { |
|||
// Map<String, Object> params = Map.of("tubeNum", tubeSol.getTubeNum(), "solutionId", tubeSol.getSolId(), "volume", tubeSol.getVolume()); |
|||
// List<Supplier<Boolean>> cmdList = cmdService.downTray(params); |
|||
// boolean result = cmdList.stream().allMatch(Supplier::get); |
|||
// if (!result) { |
|||
// return false; |
|||
// } |
|||
// } |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 将指定加热区的托盘移至加液区 |
|||
* |
|||
* @param heatId 加热区id |
|||
*/ |
|||
public boolean moveToSol(String heatId) { |
|||
// Map<String, Object> params = Map.of("heatId", heatId); |
|||
// List<Supplier<Boolean>> cmdList = cmdService.moveToActionArea(params); |
|||
// return cmdList.stream().allMatch(Supplier::get); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 移至加热 |
|||
* |
|||
* @param heatId 加热区id |
|||
*/ |
|||
public boolean moveToHeat(String heatId) { |
|||
// Map<String, Object> params = Map.of("heatId", heatId); |
|||
// List<Supplier<Boolean>> cmdList = cmdService.moveToHeatArea(params); |
|||
// return cmdList.stream().allMatch(Supplier::get); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 摇匀 |
|||
* |
|||
* @param second 摇匀时间 |
|||
*/ |
|||
public boolean shaking(int second) { |
|||
// Map<String, Object> params = Map.of(); |
|||
// List<Supplier<Boolean>> cmdList = cmdService.startShakeUp(params); |
|||
// boolean result = cmdList.stream().allMatch(Supplier::get); |
|||
// if (result) { |
|||
// this.delay(second); |
|||
// cmdList = cmdService.stopShakeUp(params); |
|||
// result = cmdList.stream().allMatch(Supplier::get); |
|||
// return result; |
|||
// } |
|||
// return false; |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 开始加热 |
|||
* |
|||
* @param heatId 加热区id |
|||
* @param temperature 目标温度 |
|||
*/ |
|||
public boolean startHeating(String heatId, double temperature) { |
|||
// Map<String, Object> params = Map.of("heatId", heatId, "temperature", temperature); |
|||
// List<Supplier<Boolean>> cmdList = cmdService.startHeat(params); |
|||
// return cmdList.stream().allMatch(Supplier::get); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 停止加热 |
|||
* |
|||
* @param heatId 加热区id |
|||
*/ |
|||
public boolean stopHeating(String heatId) { |
|||
// Map<String, Object> params = Map.of("heatId", heatId); |
|||
// List<Supplier<Boolean>> cmdList = cmdService.stopHeat(params); |
|||
// return cmdList.stream().allMatch(Supplier::get); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 停止加热 |
|||
*/ |
|||
public boolean takePhoto() { |
|||
// Map<String, Object> params = Map.of(); |
|||
// List<Supplier<Boolean>> cmdList = cmdService.takePhoto(params); |
|||
// return cmdList.stream().allMatch(Supplier::get); |
|||
return true; |
|||
} |
|||
|
|||
//移至异常 |
|||
public boolean moveToExc() { |
|||
return true; |
|||
} |
|||
|
|||
//移除异常 |
|||
public boolean moveOutToExc() { |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 等待 |
|||
* |
|||
* @param second 秒 |
|||
*/ |
|||
public boolean delay(int second) { |
|||
try { |
|||
Thread.sleep(second * 1000L); |
|||
return true; |
|||
} catch (InterruptedException e) { |
|||
Thread.currentThread().interrupt(); |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,261 @@ |
|||
package com.qyft.ms.device.service; |
|||
|
|||
import cn.hutool.json.JSONUtil; |
|||
import com.qyft.ms.device.client.TcpClient; |
|||
import com.qyft.ms.device.common.constant.DeviceCommands; |
|||
import com.qyft.ms.device.common.jsonrpc.JsonRpcRequest; |
|||
import com.qyft.ms.device.model.bo.DeviceFeedback; |
|||
import jakarta.annotation.PostConstruct; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import java.util.concurrent.*; |
|||
|
|||
/** |
|||
* 设备tcp指令发送服务 |
|||
*/ |
|||
@Slf4j |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class DeviceTcpCMDService { |
|||
|
|||
private final TcpClient tcpClient; |
|||
|
|||
private final BlockingDeque<Callable<Boolean>> taskQueue = new LinkedBlockingDeque<>(); |
|||
|
|||
private final ExecutorService executorService = Executors.newSingleThreadExecutor(); |
|||
|
|||
|
|||
@PostConstruct |
|||
private void initExecutorThread() { |
|||
new Thread(this::executeTasks).start(); |
|||
} |
|||
|
|||
private boolean putTask(String method) { |
|||
JsonRpcRequest request = new JsonRpcRequest(); |
|||
request.setMethod(method); |
|||
return this.putTask(request); |
|||
} |
|||
|
|||
private boolean putTask(String method, Map<String, Object> params) { |
|||
JsonRpcRequest request = new JsonRpcRequest(); |
|||
request.setMethod(method); |
|||
request.setParams(params); |
|||
return this.putTask(request); |
|||
} |
|||
|
|||
private boolean putTask(JsonRpcRequest request) { |
|||
Callable<Boolean> task = () -> { |
|||
DeviceFeedback deviceFeedback = tcpClient.sendCommand(request); |
|||
if (deviceFeedback == null || deviceFeedback.getError() != null) { |
|||
log.error("TCP 指令执行错误 request:{} feedback:{}", JSONUtil.toJsonStr(request), JSONUtil.toJsonStr(deviceFeedback)); |
|||
return false; |
|||
} |
|||
return true; |
|||
}; |
|||
try { |
|||
taskQueue.put(task); |
|||
return executorService.submit(taskQueue.take()).get(); |
|||
} catch (Exception e) { |
|||
log.error("TCP 指令执行错误 request:{}", JSONUtil.toJsonStr(request), e); |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
private void executeTasks() { |
|||
while (true) { |
|||
try { |
|||
Callable<Boolean> task = taskQueue.take(); |
|||
task.call(); |
|||
} catch (Exception e) { |
|||
Thread.currentThread().interrupt(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 使指定轴的电机回原点 |
|||
* @param axis 轴标识,可选值为 "X", "Y", "Z" |
|||
* @return 操作是否成功 |
|||
*/ |
|||
|
|||
public boolean motorMoveToHome(String axis) { |
|||
Map<String, Object> params = new HashMap<>(); |
|||
params.put("axis", axis); |
|||
return this.putTask(DeviceCommands.MOTOR_MOVE_TO_HOME, params); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 设置指定轴的电机运行时电流 |
|||
* @param axis 轴标识,可选值为 "X", "Y", "Z" |
|||
* @param current 电流值 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
|
|||
public boolean setMotorRunningCurrent(String axis, double current) { |
|||
Map<String, Object> params = new HashMap<>(); |
|||
params.put("axis", axis); |
|||
params.put("current", current); |
|||
DeviceFeedback deviceFeedback = tcpClient.sendCommand(DeviceCommands.SET_MOTOR_RUNNING_CURRENT, params); |
|||
if (deviceFeedback == null || deviceFeedback.getError() != null) { |
|||
log.error("TCP setMotorRunningCurrent 指令执行错误 {}", JSONUtil.toJsonStr(deviceFeedback)); |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 移动指定轴的电机到指定位置 |
|||
* @param axis 轴标识,可选值为 "X", "Y", "Z" |
|||
* @param position 轴位置,单位:mm |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean moveMotorToPosition(String axis, double position) { |
|||
Map<String, Object> params = new HashMap<>(); |
|||
params.put("axis", axis); |
|||
params.put("position", position); |
|||
return this.putTask(DeviceCommands.MOVE_MOTOR_TO_POSITION, params); |
|||
} |
|||
|
|||
/** |
|||
* 设置指定轴的电机的运行速度 |
|||
* @param axis 轴标识,可选值为 "X", "Y", "Z" |
|||
* @param speed 速度值 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean setMotorSpeed(String axis, double speed) { |
|||
Map<String, Object> params = new HashMap<>(); |
|||
params.put("axis", axis); |
|||
params.put("speed", speed); |
|||
DeviceFeedback deviceFeedback = tcpClient.sendCommand(DeviceCommands.SET_MOTOR_SPEED, params); |
|||
if (deviceFeedback == null || deviceFeedback.getError() != null) { |
|||
log.error("TCP setMotorSpeed 指令执行错误 {}", JSONUtil.toJsonStr(deviceFeedback)); |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
// 三通阀控制方法 |
|||
/** |
|||
* 切换三通阀到基质状态 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean switchThreeWayValveToSubstrate() { |
|||
return this.putTask(DeviceCommands.SWITCH_THREE_WAY_VALVE_TO_SUBSTRATE); |
|||
} |
|||
|
|||
/** |
|||
* 切换三通阀到喷涂状态 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean switchThreeWayValveToSpray() { |
|||
return this.putTask(DeviceCommands.SWITCH_THREE_WAY_VALVE_TO_SPRAY); |
|||
} |
|||
|
|||
// 除湿阀、清洗阀、喷嘴阀控制方法 |
|||
/** |
|||
* 控制指定阀的开启或关闭 |
|||
* @param valveType 阀类型,可选值为 "Dehumidification", "Cleaning", "Nozzle" |
|||
* @param isOpen 是否开启,true 为开启,false 为关闭 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean controlValve(String valveType, boolean isOpen) { |
|||
Map<String, Object> params = new HashMap<>(); |
|||
params.put("valveType", valveType); |
|||
params.put("isOpen", isOpen); |
|||
return this.putTask(DeviceCommands.CONTROL_VALVE, params); |
|||
} |
|||
|
|||
// 照明灯板控制方法 |
|||
/** |
|||
* 以指定亮度开启照明灯板 |
|||
* @param brightness 亮度值,范围 0 - 100 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean turnOnLightPanel(int brightness) { |
|||
Map<String, Object> params = new HashMap<>(); |
|||
params.put("brightness", brightness); |
|||
return this.putTask(DeviceCommands.TURN_ON_LIGHT_PANEL, params); |
|||
} |
|||
|
|||
/** |
|||
* 关闭照明灯板 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean turnOffLightPanel() { |
|||
return this.putTask(DeviceCommands.TURN_OFF_LIGHT_PANEL); |
|||
} |
|||
|
|||
// 高压电控制方法 |
|||
/** |
|||
* 以指定电压值开启高压电 |
|||
* @param voltage 电压值 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean turnOnHighVoltage(double voltage) { |
|||
Map<String, Object> params = new HashMap<>(); |
|||
params.put("voltage", voltage); |
|||
return this.putTask(DeviceCommands.TURN_ON_HIGH_VOLTAGE, params); |
|||
} |
|||
|
|||
/** |
|||
* 关闭高压电 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean turnOffHighVoltage() { |
|||
return this.putTask(DeviceCommands.TURN_OFF_HIGH_VOLTAGE); |
|||
} |
|||
|
|||
// 注射泵控制方法 |
|||
/** |
|||
* 以指定转速、方向和时间开启注射泵 |
|||
* @param rotationSpeed 转速 |
|||
* @param direction 方向 |
|||
* @param time 时间 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean turnOnSyringePump(double rotationSpeed, String direction, double time) { |
|||
Map<String, Object> params = new HashMap<>(); |
|||
params.put("rotationSpeed", rotationSpeed); |
|||
params.put("direction", direction); |
|||
params.put("time", time); |
|||
return this.putTask(DeviceCommands.TURN_ON_SYRINGE_PUMP, params); |
|||
} |
|||
|
|||
/** |
|||
* 停止注射泵 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean turnOffSyringePump() { |
|||
return this.putTask(DeviceCommands.TURN_OFF_SYRINGE_PUMP); |
|||
} |
|||
|
|||
/** |
|||
* 设置注射泵的容量、时间比例参数 |
|||
* @param capacity 容量 |
|||
* @param timeRatio 时间比例 |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean setSyringePumpParameters(double capacity, double timeRatio) { |
|||
Map<String, Object> params = new HashMap<>(); |
|||
params.put("capacity", capacity); |
|||
params.put("timeRatio", timeRatio); |
|||
return this.putTask(DeviceCommands.SET_SYRINGE_PUMP_PARAMETERS, params); |
|||
} |
|||
|
|||
/** |
|||
* 推送指定容量的液体 |
|||
* @param volume 容量,单位:ml |
|||
* @return 操作是否成功 |
|||
*/ |
|||
public boolean pushVolume(double volume) { |
|||
Map<String, Object> params = new HashMap<>(); |
|||
params.put("volume", volume); |
|||
return this.putTask(DeviceCommands.PUSH_VOLUME, params); |
|||
} |
|||
} |
@ -0,0 +1,28 @@ |
|||
package com.qyft.ms.device.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.qyft.ms.device.model.bo.DeviceCtrlFuncCMD; |
|||
import com.qyft.ms.device.model.entity.CtrlFunc; |
|||
import com.qyft.ms.device.model.form.CtrlFuncForm; |
|||
import com.qyft.ms.device.model.vo.DeviceCtrlFuncVO; |
|||
|
|||
import java.util.List; |
|||
|
|||
|
|||
public interface ICtrlFuncService extends IService<CtrlFunc> { |
|||
|
|||
List<DeviceCtrlFuncCMD> findAllStepCMD(); |
|||
|
|||
List<CtrlFunc> findAll(); |
|||
|
|||
DeviceCtrlFuncVO findVOById(Long id); |
|||
|
|||
long countFuncCmdByFuncCmd(String funcCmd); |
|||
|
|||
boolean addCtrlFunc(CtrlFuncForm ctrlFuncForm); |
|||
|
|||
boolean updateCtrlFunc(Long id, CtrlFuncForm ctrlFuncForm); |
|||
|
|||
boolean deleteCtrlFunc(String idsStr); |
|||
|
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.qyft.ms.device.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.qyft.ms.device.model.entity.CtrlFuncStep; |
|||
|
|||
import java.util.List; |
|||
|
|||
public interface ICtrlFuncStepService extends IService<CtrlFuncStep> { |
|||
List<CtrlFuncStep> selectListByFuncCmd(String funcCmd); |
|||
|
|||
|
|||
} |
@ -0,0 +1,132 @@ |
|||
package com.qyft.ms.device.service.impl; |
|||
|
|||
import cn.hutool.json.JSONUtil; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.qyft.ms.device.mapper.CtrlFuncMapper; |
|||
import com.qyft.ms.device.model.bo.DeviceCtrlFuncCMD; |
|||
import com.qyft.ms.device.model.entity.CtrlFunc; |
|||
import com.qyft.ms.device.model.entity.CtrlFuncStep; |
|||
import com.qyft.ms.device.model.form.CtrlFuncForm; |
|||
import com.qyft.ms.device.model.vo.DeviceCtrlFuncVO; |
|||
import com.qyft.ms.device.service.ICtrlFuncService; |
|||
import com.qyft.ms.device.service.ICtrlFuncStepService; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@RequiredArgsConstructor |
|||
@Service |
|||
public class CtrlFuncServiceImpl extends ServiceImpl<CtrlFuncMapper, CtrlFunc> implements ICtrlFuncService { |
|||
|
|||
private final ICtrlFuncStepService ctrlFuncStepService; |
|||
|
|||
private static final List<DeviceCtrlFuncCMD> ctrlFuncDeviceCMDList = new ArrayList<>(); |
|||
|
|||
static { |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("开门", "openDoor", "{}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("关门", "closeDoor", "{}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("导轨机械臂运动到指定点位", "moveRailArmToPoint", "{\"x\":0,\"y\":0,\"z\":0}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("导轨机械臂相对运动", "moveRailArmRelative", "{\"x\":0,\"y\":0,\"z\":0}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("导轨机械臂移至指定加热区上方", "moveToHeatArea", "{\"heatId\":2}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("导轨机械臂移至加液区上方", "moveToActionArea", "{}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("导轨机械臂移至拍子存放区上方", "moveToCapArea", "{}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("打开导轨机械臂夹爪", "openClaw", "{}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("收合导轨机械臂夹爪", "closeClaw", "{}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("指定加热区密封拍子", "sealLidOn", "{\"heatId\":2}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("指定加热区解除密封拍子", "sealLidOff", "{\"heatId\":2}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("拍子存放区高度向上一个级别", "capHeightUp", "{}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("拍子存放区高度向下移动一个级别", "capHeightDown", "{}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("指定加热区开始加热", "startHeating", "{\"heatId\":2}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("指定加热区停止加热", "stopHeating", "{\"heatId\":2}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("指定加热区抬起托盘", "raiseTray", "{\"heatId\":2}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("指定加热区放下托盘", "lowerTray", "{\"heatId\":2}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("依次添加溶液", "addLiquid", "{\"tubeSolList\":[{\"tubeNum\":1,\"solId\":15,\"volume\":20}]}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("开始摇匀", "startShaking", "{}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("停止摇匀", "stopShaking", "{}")); |
|||
ctrlFuncDeviceCMDList.add(new DeviceCtrlFuncCMD("拍照", "takePhoto", "{}")); |
|||
} |
|||
|
|||
@Override |
|||
public List<DeviceCtrlFuncCMD> findAllStepCMD() { |
|||
return ctrlFuncDeviceCMDList; |
|||
} |
|||
|
|||
@Override |
|||
public List<CtrlFunc> findAll() { |
|||
return this.baseMapper.selectList(null); |
|||
} |
|||
|
|||
@Override |
|||
public DeviceCtrlFuncVO findVOById(Long id) { |
|||
CtrlFunc ctrlFunc = this.getById(id); |
|||
List<CtrlFuncStep> ctrlFuncStepList = ctrlFuncStepService.selectListByFuncCmd(ctrlFunc.getFuncCmd()); |
|||
DeviceCtrlFuncVO ctrlFuncVO = new DeviceCtrlFuncVO(); |
|||
ctrlFuncVO.setId(ctrlFunc.getId()); |
|||
ctrlFuncVO.setName(ctrlFunc.getName()); |
|||
ctrlFuncVO.setFuncCmd(ctrlFunc.getFuncCmd()); |
|||
ctrlFuncVO.setFuncCmd(ctrlFunc.getFuncCmd()); |
|||
ctrlFuncVO.setCtrlFuncStepList(ctrlFuncStepList); |
|||
return ctrlFuncVO; |
|||
} |
|||
|
|||
@Override |
|||
public long countFuncCmdByFuncCmd(String funcCmd) { |
|||
return this.count(new LambdaQueryWrapper<CtrlFunc>().eq(CtrlFunc::getFuncCmd, funcCmd)); |
|||
} |
|||
|
|||
@Override |
|||
public boolean addCtrlFunc(CtrlFuncForm ctrlFuncForm) { |
|||
CtrlFunc ctrlFunc = new CtrlFunc(); |
|||
ctrlFunc.setFuncCmd(ctrlFuncForm.getFuncCmd()); |
|||
ctrlFunc.setName(ctrlFuncForm.getName()); |
|||
if (this.save(ctrlFunc)) { |
|||
return reSaveCtrlFunc(ctrlFuncForm, ctrlFunc); |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
@Override |
|||
public boolean updateCtrlFunc(Long id, CtrlFuncForm ctrlFuncForm) { |
|||
CtrlFunc ctrlFunc = this.getById(id); |
|||
if (ctrlFunc != null) { |
|||
ctrlFunc.setFuncCmd(ctrlFuncForm.getFuncCmd()); |
|||
ctrlFunc.setName(ctrlFuncForm.getName()); |
|||
if (this.updateById(ctrlFunc)) { |
|||
return reSaveCtrlFunc(ctrlFuncForm, ctrlFunc); |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
@Override |
|||
public boolean deleteCtrlFunc(String idsStr) { |
|||
List<Long> ids = Arrays.stream(idsStr.split(",")) |
|||
.map(Long::parseLong) |
|||
.collect(Collectors.toList()); |
|||
for (Long id : ids) { |
|||
String funcCmd = this.getById(id).getFuncCmd(); |
|||
ctrlFuncStepService.remove(new LambdaQueryWrapper<CtrlFuncStep>().eq(CtrlFuncStep::getFuncCmd, funcCmd)); |
|||
} |
|||
return this.removeByIds(ids); |
|||
} |
|||
|
|||
private boolean reSaveCtrlFunc(CtrlFuncForm ctrlFuncForm, CtrlFunc ctrlFunc) { |
|||
ctrlFuncStepService.remove(new LambdaQueryWrapper<CtrlFuncStep>().eq(CtrlFuncStep::getFuncCmd, ctrlFunc.getFuncCmd())); |
|||
List<CtrlFuncForm.CtrlFuncStepForm> ctrlFuncStepFormList = ctrlFuncForm.getCtrlFuncStepList(); |
|||
List<CtrlFuncStep> ctrlFuncStepList = ctrlFuncStepFormList.stream() |
|||
.map(ctrlFuncStepForm -> { |
|||
CtrlFuncStep ctrlFuncStep = new CtrlFuncStep(); |
|||
ctrlFuncStep.setFuncCmd(ctrlFunc.getFuncCmd()); |
|||
ctrlFuncStep.setDeviceCmd(ctrlFuncStepForm.getDeviceCmd()); |
|||
ctrlFuncStep.setRemarks(ctrlFuncStepForm.getRemarks()); |
|||
ctrlFuncStep.setParams(JSONUtil.toJsonStr(ctrlFuncStepForm.getParams())); |
|||
return ctrlFuncStep; |
|||
}).toList(); |
|||
return ctrlFuncStepService.saveBatch(ctrlFuncStepList); |
|||
} |
|||
} |
@ -0,0 +1,20 @@ |
|||
package com.qyft.ms.device.service.impl; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.qyft.ms.device.mapper.CtrlFuncStepMapper; |
|||
import com.qyft.ms.device.model.entity.CtrlFuncStep; |
|||
import com.qyft.ms.device.service.ICtrlFuncStepService; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Service |
|||
public class CtrlFuncStepServiceImpl extends ServiceImpl<CtrlFuncStepMapper, CtrlFuncStep> implements ICtrlFuncStepService { |
|||
|
|||
@Override |
|||
public List<CtrlFuncStep> selectListByFuncCmd(String funcCmd) { |
|||
return this.list(new LambdaQueryWrapper<CtrlFuncStep>().eq(CtrlFuncStep::getFuncCmd, funcCmd)); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,34 @@ |
|||
package com.qyft.ms.enums; |
|||
|
|||
import cn.hutool.core.util.StrUtil; |
|||
|
|||
public enum DirectiveTypeEnum { |
|||
ADD("add", "抬起托盘"); |
|||
|
|||
private final String typeCode; |
|||
private final String typeName; |
|||
|
|||
DirectiveTypeEnum(String typeCode, String typeName) { |
|||
this.typeCode = typeCode; |
|||
this.typeName = typeName; |
|||
} |
|||
|
|||
public static String getByCode(String code) { |
|||
if (StrUtil.isNotBlank(code)) { |
|||
for (DirectiveTypeEnum item : DirectiveTypeEnum.values()) { |
|||
if (item.typeCode().equals(code.trim())) { |
|||
return item.typeCode(); |
|||
} |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public String typeCode() { |
|||
return typeCode; |
|||
} |
|||
|
|||
public String typeName() { |
|||
return typeName; |
|||
} |
|||
} |
@ -0,0 +1,28 @@ |
|||
package com.qyft.ms.generator; |
|||
|
|||
import com.baomidou.mybatisplus.generator.FastAutoGenerator; |
|||
import com.baomidou.mybatisplus.generator.config.OutputFile; |
|||
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; |
|||
|
|||
import java.util.Collections; |
|||
|
|||
public class CodeGenerator { |
|||
public static void main(String[] args) { |
|||
FastAutoGenerator.create("jdbc:sqlite:" + System.getProperty("user.dir") + "/matrix-spray.db", "", "") |
|||
.globalConfig(builder -> { |
|||
builder.author("qyft") // 设置作者 |
|||
.enableSwagger() // 开启 swagger 模式 |
|||
.outputDir("D://new"); // 指定输出目录 |
|||
}) |
|||
.packageConfig(builder -> { |
|||
builder.parent("com.qyft.ms") // 设置父包名 |
|||
.moduleName("device") // 设置父包模块名 |
|||
.pathInfo(Collections.singletonMap(OutputFile.xml, "D://new/resources/mapper")); // 设置mapperXml生成路径 |
|||
}) |
|||
.strategyConfig(builder -> { |
|||
builder.addTablePrefix("t_", "c_"); // 设置过滤表前缀 |
|||
}) |
|||
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 |
|||
.execute(); |
|||
} |
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.qyft.ms.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.qyft.ms.model.entity.Logs; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
|
|||
/** |
|||
* 日志持久层接口 |
|||
*/ |
|||
@Mapper |
|||
public interface LogsMapper extends BaseMapper<Logs> { |
|||
} |
@ -0,0 +1,29 @@ |
|||
package com.qyft.ms.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.qyft.ms.model.dto.SysSettingsDTO; |
|||
import com.qyft.ms.model.entity.SysSettings; |
|||
import com.qyft.ms.model.vo.SysSettingVO; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
|
|||
import java.util.List; |
|||
|
|||
|
|||
/** |
|||
* <p> |
|||
* Mapper 接口 |
|||
* </p> |
|||
* |
|||
* @author 郭安鹏 |
|||
* @since 2025-02-17 |
|||
*/ |
|||
|
|||
@Mapper |
|||
public interface SysSettingsMapper extends BaseMapper<SysSettings> { |
|||
List<SysSettingVO> getConfig(String type); |
|||
|
|||
void updateById(SysSettingsDTO dto); |
|||
|
|||
int getIdByCode(String type); |
|||
} |
|||
|
@ -0,0 +1,52 @@ |
|||
package com.qyft.ms.model.bo; |
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* 工艺步骤执行方法 |
|||
*/ |
|||
@Data |
|||
public class CraftsStepMethod { |
|||
/** |
|||
* 上升托盘 |
|||
*/ |
|||
public static final String UP_TRAY = "upTray"; |
|||
/** |
|||
* 降下托盘 |
|||
*/ |
|||
public static final String DOWN_TRAY = "downTray"; |
|||
/** |
|||
* 加液 |
|||
*/ |
|||
public static final String ADD_LIQUID = "addLiquid"; |
|||
/** |
|||
* 移动到溶液位置 |
|||
*/ |
|||
public static final String MOVE_TO_SOL = "moveToSol"; |
|||
/** |
|||
* 移动到加热器位置 |
|||
*/ |
|||
public static final String MOVE_TO_HEAT = "moveToHeat"; |
|||
/** |
|||
* 摇晃 |
|||
*/ |
|||
public static final String SHAKING = "shaking"; |
|||
/** |
|||
* 开始加热 |
|||
*/ |
|||
public static final String START_HEATING = "startHeating"; |
|||
/** |
|||
* 停止加热 |
|||
*/ |
|||
public static final String STOP_HEATING = "stopHeating"; |
|||
/** |
|||
* 拍照 |
|||
*/ |
|||
public static final String TAKE_PHOTO = "takePhoto"; |
|||
/** |
|||
* 等待 |
|||
*/ |
|||
public static final String DELAY = "delay"; |
|||
|
|||
|
|||
} |
@ -0,0 +1,35 @@ |
|||
package com.qyft.ms.model.bo; |
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* 工艺步骤执行状态 |
|||
*/ |
|||
@Data |
|||
public class CraftsStepStatus { |
|||
|
|||
/** |
|||
* 未执行 |
|||
*/ |
|||
public static final int NOT_EXECUTED = 0; |
|||
/** |
|||
* 正在执行 |
|||
*/ |
|||
public static final int IN_PROGRESS = 1; |
|||
/** |
|||
* 暂停执行 |
|||
*/ |
|||
public static final int PAUSED = 2; |
|||
/** |
|||
* 停止执行 |
|||
*/ |
|||
public static final int STOPPED = 3; |
|||
/** |
|||
* 执行错误 |
|||
*/ |
|||
public static final int ERROR = 4; |
|||
/** |
|||
* 执行完成 |
|||
*/ |
|||
public static final int FINISH = 6; |
|||
} |
@ -0,0 +1,23 @@ |
|||
package com.qyft.ms.model.bo; |
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* 试管添加溶液 |
|||
*/ |
|||
@Data |
|||
public class TubeSol { |
|||
/** |
|||
* 需要添加溶液的试管编号 |
|||
*/ |
|||
private Integer tubeNum; |
|||
/** |
|||
* 溶液id |
|||
*/ |
|||
private Long solId; |
|||
/** |
|||
* 加液量 |
|||
*/ |
|||
private Integer volume; |
|||
|
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class BaseDataDTO { |
|||
@Schema(description = "加热区id") |
|||
private Long id; |
|||
@Schema(description = "温度") |
|||
private Long temperature; |
|||
@Schema(description = "工艺id") |
|||
private Long craftId; |
|||
} |
@ -0,0 +1,13 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class CmdInjectFluidDTO { |
|||
@Schema(description = "指令id") |
|||
private String commandId; |
|||
|
|||
@Schema(description = "加液数据list") |
|||
private InjectFluid[] injectFluids; |
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class ContainerDTO { |
|||
@Schema(description = "容器id") |
|||
private Long id; |
|||
@Schema(description = "溶液id") |
|||
private Long solutionId; |
|||
@Schema(description = "已使用容量") |
|||
private Integer capacityUsed; |
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class InjectFluid { |
|||
@Schema(description = "试管编号") |
|||
private Integer tubeNum; |
|||
@Schema(description = "溶液id") |
|||
private Integer solutionId; |
|||
@Schema(description = "容量") |
|||
private Integer volume; |
|||
} |
@ -0,0 +1,10 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class LogDTO { |
|||
@Schema(description = "日志信息") |
|||
private String text; |
|||
} |
@ -0,0 +1,11 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Schema(description = "暂停执行工艺") |
|||
@Data |
|||
public class PauseCraftsDto { |
|||
@Schema(description = "加热区id") |
|||
private String heatId; |
|||
} |
@ -0,0 +1,11 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Schema(description = "恢复执行工艺") |
|||
@Data |
|||
public class ResumeCraftsDto { |
|||
@Schema(description = "加热区id") |
|||
private String heatId; |
|||
} |
@ -0,0 +1,13 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Schema(description = "开始工艺") |
|||
@Data |
|||
public class StartCraftsDTO { |
|||
@Schema(description = "工艺id") |
|||
private Long craftId; |
|||
@Schema(description = "加热区id") |
|||
private String heatId; |
|||
} |
@ -0,0 +1,13 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class StartHeatDTO { |
|||
@Schema(description = "指令id") |
|||
private String commandId; |
|||
|
|||
@Schema(description = "加液数据list") |
|||
private Integer[] heatIds; |
|||
} |
@ -0,0 +1,11 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Schema(description = "恢复执行工艺") |
|||
@Data |
|||
public class StopCraftsDto { |
|||
@Schema(description = "加热区id") |
|||
private String heatId; |
|||
} |
@ -0,0 +1,10 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class StopTaskDTO { |
|||
@Schema(description = "实验id") |
|||
private Long taskId; |
|||
} |
@ -0,0 +1,16 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class SysSettingsDTO { |
|||
@Schema(description = "主键id") |
|||
private Long id; |
|||
@Schema(description = "值") |
|||
private String value; |
|||
@Schema(description = "温度") |
|||
private Long temperature; |
|||
@Schema(description = "工艺id") |
|||
private Long craftId; |
|||
} |
@ -0,0 +1,10 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class TaskDTO { |
|||
@Schema(description = "实验名称") |
|||
private String name; |
|||
} |
@ -0,0 +1,22 @@ |
|||
package com.qyft.ms.model.dto; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
@Data |
|||
public class WebsocketDTO { |
|||
|
|||
@Schema(description = "指令id,不指定后台会自动生成uuid") |
|||
private String commandId; |
|||
|
|||
@NotBlank() |
|||
@Schema(description = "指令类型", example = "upTray") |
|||
private String commandName; |
|||
|
|||
@Schema(description = "参数") |
|||
private Map<String, Object> params; |
|||
} |
@ -0,0 +1,35 @@ |
|||
package com.qyft.ms.model.entity; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Schema(description = "容器表") |
|||
@TableName("container") |
|||
@Data |
|||
public class Container { |
|||
@NotBlank |
|||
@Schema(description = "容器id") |
|||
private Long id; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "类型 0 溶液 1 废液") |
|||
private Long type; |
|||
|
|||
@Schema(description = "溶液id") |
|||
private Long solutionId; |
|||
|
|||
@Schema(description = "机器id") |
|||
private String pumpId; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "总容量") |
|||
private Integer capacityTotal; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "使用容量") |
|||
private Integer capacityUsed; |
|||
} |
@ -0,0 +1,25 @@ |
|||
package com.qyft.ms.model.entity; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import com.qyft.ms.system.common.base.BaseEntity; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@EqualsAndHashCode(callSuper = true) |
|||
@Schema(description = "工艺") |
|||
@TableName("crafts") |
|||
@Data |
|||
public class Crafts extends BaseEntity { |
|||
|
|||
@NotBlank |
|||
@Schema(description = "工艺名称") |
|||
private String name; |
|||
|
|||
@Schema(description = "工艺步骤") |
|||
private String steps; |
|||
|
|||
@Schema(description = "矿石ID") |
|||
private Long oresId; |
|||
} |
@ -0,0 +1,30 @@ |
|||
package com.qyft.ms.model.entity; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Schema(description = "日志") |
|||
@TableName("logs") |
|||
@Data |
|||
public class Logs { |
|||
|
|||
@NotBlank |
|||
@Schema(description = "id") |
|||
private Long id; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "创建人") |
|||
private Long createUser; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "日志内容") |
|||
private String text; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "创建时间") |
|||
private String createTime; |
|||
} |
@ -0,0 +1,20 @@ |
|||
package com.qyft.ms.model.entity; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import com.qyft.ms.system.common.base.BaseEntity; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@EqualsAndHashCode(callSuper = true) |
|||
@Schema(description = "矿石") |
|||
@TableName("ores") |
|||
@Data |
|||
public class Ores extends BaseEntity { |
|||
|
|||
@NotBlank() |
|||
@Schema(description = "矿石名称") |
|||
private String name; |
|||
|
|||
} |
@ -0,0 +1,20 @@ |
|||
package com.qyft.ms.model.entity; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import com.qyft.ms.system.common.base.BaseEntity; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@EqualsAndHashCode(callSuper = true) |
|||
@Schema(description = "溶液") |
|||
@TableName("solutions") |
|||
@Data |
|||
public class Solutions extends BaseEntity { |
|||
|
|||
@NotBlank() |
|||
@Schema(description = "溶液名称") |
|||
private String name; |
|||
|
|||
} |
@ -0,0 +1,43 @@ |
|||
package com.qyft.ms.model.entity; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
/** |
|||
* <p> |
|||
* 系统配置 |
|||
* </p> |
|||
* |
|||
* @author 郭安鹏 |
|||
* @since 2025-02-17 |
|||
*/ |
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Schema(description = "系统配置") |
|||
@TableName("sys_settings") |
|||
@Data |
|||
public class SysSettings { |
|||
|
|||
@Schema(description = "主键id") |
|||
private Long id; |
|||
|
|||
@Schema(description = "父id") |
|||
private Long parentId; |
|||
|
|||
@Schema(description = "名称") |
|||
private String name; |
|||
|
|||
@Schema(description = "code") |
|||
private String code; |
|||
|
|||
@Schema(description = "配置值") |
|||
private String value1; |
|||
|
|||
@Schema(description = "配置值") |
|||
private String value2; |
|||
|
|||
@Schema(description = "配置值") |
|||
private String value3; |
|||
|
|||
} |
@ -0,0 +1,30 @@ |
|||
package com.qyft.ms.model.entity; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Schema(description = "实验步骤") |
|||
@TableName("task_steps") |
|||
@Data |
|||
public class TaskSteps { |
|||
|
|||
@NotBlank |
|||
@Schema(description = "id") |
|||
private Long id; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "实验id") |
|||
private Long taskId; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "步骤描述") |
|||
private String stepDescription; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "创建时间") |
|||
private String createTime; |
|||
} |
@ -0,0 +1,35 @@ |
|||
package com.qyft.ms.model.entity; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import com.qyft.ms.system.common.base.BaseEntity; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@EqualsAndHashCode(callSuper = true) |
|||
@Schema(description = "实验") |
|||
@TableName("tasks") |
|||
@Data |
|||
public class Tasks extends BaseEntity { |
|||
|
|||
@NotBlank |
|||
@Schema(description = "实验名称") |
|||
private String name; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "开始时间") |
|||
private String startTime; |
|||
|
|||
@Schema(description = "创建人") |
|||
private Long createUser; |
|||
|
|||
@Schema(description = "结束时间") |
|||
private String endTime; |
|||
|
|||
@Schema(description = "状态 1 执行中 2 执行完毕") |
|||
private Integer status; |
|||
|
|||
@Schema(description = "是否删除 0 未删除 1 已删除") |
|||
private Integer isDeleted; |
|||
} |
@ -0,0 +1,23 @@ |
|||
package com.qyft.ms.model.form; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Schema(description = "指令") |
|||
@Data |
|||
public class CMDForm { |
|||
|
|||
@Schema(description = "指令id,不指定后台会自动生成uuid") |
|||
private String commandId; |
|||
|
|||
@NotBlank() |
|||
@Schema(description = "指令类型", example = "upTray") |
|||
private String command; |
|||
|
|||
@Schema(description = "参数") |
|||
private List<Object> params; |
|||
|
|||
} |
@ -0,0 +1,27 @@ |
|||
package com.qyft.ms.model.vo; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.util.List; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Schema(description = "容器") |
|||
@Data |
|||
public class BaseDataVO { |
|||
@Schema(description = "加热区") |
|||
List<SysSettingVO> heat_area; |
|||
|
|||
@Schema(description = "加液区") |
|||
List<SysSettingVO> solution_area; |
|||
|
|||
@Schema(description = "拍子区域") |
|||
List<SysSettingVO> lid_area; |
|||
|
|||
@Schema(description = "系统配置") |
|||
List<SysSettingVO> sys_setting; |
|||
|
|||
@Schema(description = "容器数据") |
|||
List<ContainerListVO> containers; |
|||
} |
@ -0,0 +1,13 @@ |
|||
package com.qyft.ms.model.vo; |
|||
|
|||
import com.qyft.ms.model.entity.Container; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@EqualsAndHashCode(callSuper = true) |
|||
@Schema(description = "容器") |
|||
@Data |
|||
public class ContainerListVO extends Container { |
|||
|
|||
} |
@ -0,0 +1,23 @@ |
|||
package com.qyft.ms.model.vo; |
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* 工艺步骤执行状态 |
|||
*/ |
|||
@Data |
|||
public class CraftsStepResult { |
|||
/** |
|||
* 加热区id |
|||
*/ |
|||
private String heatId; |
|||
/** |
|||
* 0 (未执行),1 (正在执行),2 (暂停执行),3 (停止执行),4(执行错误),6(执行完成) |
|||
*/ |
|||
private Integer status; |
|||
/** |
|||
* 当前工艺执行的方法数组下标 |
|||
*/ |
|||
private Integer methodIndex; |
|||
|
|||
} |
@ -0,0 +1,22 @@ |
|||
package com.qyft.ms.model.vo; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class ExecutionResult { |
|||
/** |
|||
* 任务id |
|||
*/ |
|||
private String commandId; |
|||
|
|||
private String commandName; |
|||
/** |
|||
* 执行结果 |
|||
*/ |
|||
private String status; |
|||
/** |
|||
* 结果描述 |
|||
*/ |
|||
private String message; |
|||
|
|||
} |
@ -0,0 +1,30 @@ |
|||
package com.qyft.ms.model.vo; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import com.qyft.ms.model.entity.Crafts; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
import java.time.LocalDateTime; |
|||
import java.util.List; |
|||
|
|||
@Schema(description = "矿石工艺视图") |
|||
@Data |
|||
public class OresCraftsListVO { |
|||
|
|||
@Schema(description = "矿石id") |
|||
private Long id; |
|||
|
|||
@Schema(description = "矿石名称") |
|||
private String oresName; |
|||
|
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
private LocalDateTime createTime; |
|||
|
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
private LocalDateTime updateTime; |
|||
|
|||
@Schema(description = "该矿石下工艺列表") |
|||
private List<Crafts> craftsList; |
|||
|
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.qyft.ms.model.vo; |
|||
|
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.util.List; |
|||
|
|||
@EqualsAndHashCode(callSuper = true) |
|||
@Data |
|||
public class SysSettingResult extends SysSettingVO { |
|||
|
|||
private List<SysSettingVO> children; |
|||
|
|||
} |
@ -0,0 +1,43 @@ |
|||
package com.qyft.ms.model.vo; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.util.List; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Data |
|||
public class SysSettingVO { |
|||
|
|||
@Schema(description = "主键id") |
|||
private int id; |
|||
|
|||
@Schema(description = "父id") |
|||
private int parentId; |
|||
|
|||
@Schema(description = "名称") |
|||
private String name; |
|||
|
|||
@Schema(description = "code") |
|||
private String code; |
|||
|
|||
@Schema(description = "配置值") |
|||
private String value; |
|||
|
|||
@Schema(description = "设备id") |
|||
private String hardwareId; |
|||
|
|||
@Schema(description = "加热区温度") |
|||
private String temperature; |
|||
|
|||
@Schema(description = "工艺id") |
|||
private int craftId; |
|||
|
|||
@Schema(description = "试管坐标list") |
|||
private List<String> tubePositionList; |
|||
|
|||
@Schema(description = "拍子坐标") |
|||
private String LidPosition; |
|||
|
|||
} |
@ -0,0 +1,35 @@ |
|||
package com.qyft.ms.model.vo; |
|||
|
|||
import com.qyft.ms.model.entity.TaskSteps; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.util.List; |
|||
|
|||
@EqualsAndHashCode(callSuper = false) |
|||
@Data |
|||
public class TaskListVO { |
|||
@Schema(description = "实验id") |
|||
private Long id; |
|||
|
|||
@Schema(description = "实验名称") |
|||
private String name; |
|||
|
|||
@NotBlank |
|||
@Schema(description = "开始时间") |
|||
private String startTime; |
|||
|
|||
@Schema(description = "创建人") |
|||
private Long createUser; |
|||
|
|||
@Schema(description = "结束时间") |
|||
private String endTime; |
|||
|
|||
@Schema(description = "状态 1 执行中 2 执行完毕") |
|||
private Integer status; |
|||
|
|||
@Schema(description = "实验步骤") |
|||
private List<TaskSteps> steps; |
|||
} |
@ -0,0 +1,18 @@ |
|||
package com.qyft.ms.model.vo; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class WebsocketResult { |
|||
/** |
|||
* 推送类型(指令 cmd,报警 warn ,状态 status) |
|||
*/ |
|||
@Schema(description = "推送类型(指令 cmd,报警 warn ,状态 status)") |
|||
private String type; |
|||
/** |
|||
* 执行结果 |
|||
*/ |
|||
@Schema(description = "推送数据") |
|||
private Object data; |
|||
} |
@ -0,0 +1,61 @@ |
|||
package com.qyft.ms.service; |
|||
|
|||
import cn.hutool.json.JSONUtil; |
|||
import com.qyft.ms.common.constant.WebSocketMessageType; |
|||
import com.qyft.ms.common.result.CMDResultCode; |
|||
import com.qyft.ms.device.model.bo.DeviceCtrlFuncCMD; |
|||
import com.qyft.ms.device.service.ICtrlFuncService; |
|||
import com.qyft.ms.model.form.CMDForm; |
|||
import com.qyft.ms.model.vo.ExecutionResult; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.List; |
|||
import java.util.function.Supplier; |
|||
|
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
@Service |
|||
public class CMDService { |
|||
|
|||
private final WebSocketService webSocketService; |
|||
private final ICtrlFuncService ctrlFuncService; |
|||
CMDForm form; |
|||
|
|||
private void run(List<Supplier<Boolean>> cmdList) { |
|||
ExecutionResult executionResult = new ExecutionResult(); |
|||
executionResult.setCommandId(form.getCommandId()); |
|||
executionResult.setCommandName(form.getCommand()); |
|||
|
|||
// 执行所有命令 |
|||
for (Supplier<Boolean> command : cmdList) { |
|||
boolean result = command.get(); |
|||
if (!result) { |
|||
log.error("指令执行异常: {}", JSONUtil.toJsonStr(form)); |
|||
executionResult.setStatus(CMDResultCode.FAILURE.getCode()); |
|||
executionResult.setMessage(CMDResultCode.FAILURE.getMsg()); |
|||
webSocketService.pushMsg(WebSocketMessageType.CMD, executionResult); |
|||
return; |
|||
} |
|||
} |
|||
executionResult.setStatus(CMDResultCode.SUCCESS.getCode()); |
|||
executionResult.setMessage(CMDResultCode.SUCCESS.getMsg()); |
|||
webSocketService.pushMsg(WebSocketMessageType.CMD, executionResult); |
|||
} |
|||
|
|||
public boolean executeCommand(CMDForm cmdForm) { |
|||
String commandName = cmdForm.getCommand(); |
|||
List<DeviceCtrlFuncCMD> deviceCtrlFuncCMDList = ctrlFuncService.findAllStepCMD(); |
|||
for (DeviceCtrlFuncCMD deviceCtrlFuncCMD : deviceCtrlFuncCMDList) { |
|||
if (deviceCtrlFuncCMD.getDeviceCmd().equals(commandName)) { |
|||
new Thread(() -> run(cmdForm)).start(); |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,11 @@ |
|||
package com.qyft.ms.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.qyft.ms.model.entity.Logs; |
|||
|
|||
/** |
|||
* 日志业务接口 |
|||
*/ |
|||
public interface ILogsService extends IService<Logs> { |
|||
int insertLog(String log); |
|||
} |
@ -0,0 +1,24 @@ |
|||
package com.qyft.ms.service; |
|||
|
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.qyft.ms.model.dto.SysSettingsDTO; |
|||
import com.qyft.ms.model.entity.SysSettings; |
|||
import com.qyft.ms.model.vo.SysSettingResult; |
|||
import com.qyft.ms.model.vo.SysSettingVO; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 系统配置接口层 |
|||
*/ |
|||
public interface ISysSettingsService extends IService<SysSettings> { |
|||
|
|||
List<SysSettingVO> getConfig(String type); |
|||
|
|||
List<SysSettingResult> getAllConfig(); |
|||
|
|||
Boolean updateConfig(List<SysSettingsDTO> dto); |
|||
|
|||
boolean setSysDate(String newTime); |
|||
} |
@ -0,0 +1,38 @@ |
|||
package com.qyft.ms.service; |
|||
|
|||
import com.qyft.ms.common.constant.WebSocketMessageType; |
|||
import com.qyft.ms.device.model.bo.DeviceStatus; |
|||
import com.qyft.ms.device.service.DeviceStatusService; |
|||
import jakarta.annotation.PostConstruct; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.concurrent.Executors; |
|||
import java.util.concurrent.ScheduledExecutorService; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Slf4j |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class StatusService { |
|||
|
|||
private final WebSocketService webSocketService; |
|||
private final DeviceStatusService deviceStatusService; |
|||
|
|||
// @PostConstruct |
|||
public void init() { |
|||
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); |
|||
executorService.scheduleAtFixedRate(() -> { |
|||
try { |
|||
DeviceStatus deviceStatus = deviceStatusService.getDeviceStatus(); |
|||
webSocketService.pushMsg(WebSocketMessageType.STATUS, deviceStatus); |
|||
} catch (Exception e) { |
|||
if (!executorService.isShutdown()) { |
|||
executorService.shutdown(); // 关闭 ScheduledExecutorService |
|||
} |
|||
log.error("定时推送设备状态异常", e); |
|||
} |
|||
}, 10, 100, TimeUnit.MILLISECONDS); |
|||
} |
|||
} |
@ -0,0 +1,32 @@ |
|||
package com.qyft.ms.service; |
|||
|
|||
import cn.hutool.json.JSONUtil; |
|||
import com.qyft.ms.config.WebSocketServer; |
|||
import com.qyft.ms.model.vo.WebsocketResult; |
|||
import jakarta.annotation.PostConstruct; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
@Service |
|||
public class WebSocketService { |
|||
public void pushMsg(String type, Object result) { |
|||
|
|||
WebsocketResult websocketResult = new WebsocketResult(); |
|||
websocketResult.setType(type); |
|||
websocketResult.setData(result); |
|||
// 发送消息给客户端 |
|||
WebSocketServer.sendMessageToClients(JSONUtil.toJsonStr(websocketResult)); |
|||
} |
|||
|
|||
@PostConstruct |
|||
public void init() { |
|||
// 设置 WebSocketService 实例到 WebSocketServer |
|||
WebSocketServer.setWebSocketService(this); |
|||
} |
|||
|
|||
// 新增方法:处理接收到的消息 |
|||
public void handleReceivedMessage(String message) { |
|||
// 这里可以添加处理接收到消息的逻辑 |
|||
System.out.println("Received message: " + message); |
|||
// 根据需要解析消息并进行处理 |
|||
} |
|||
} |
@ -0,0 +1,29 @@ |
|||
package com.qyft.ms.service.impl; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.qyft.ms.mapper.LogsMapper; |
|||
import com.qyft.ms.model.entity.Logs; |
|||
import com.qyft.ms.service.ILogsService; |
|||
import com.qyft.ms.system.model.entity.User; |
|||
import com.qyft.ms.system.service.IUserService; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
/** |
|||
* 实验业务实现类 |
|||
*/ |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class ILogsServiceImpl extends ServiceImpl<LogsMapper, Logs> implements ILogsService { |
|||
private final LogsMapper logsMapper; |
|||
private final IUserService userService; |
|||
|
|||
@Override |
|||
public int insertLog(String log) { |
|||
Logs logs = new Logs(); |
|||
logs.setText(log); |
|||
User user = userService.currentUser(); |
|||
logs.setCreateUser(user.getId()); |
|||
return logsMapper.insert(logs); |
|||
} |
|||
} |
@ -0,0 +1,75 @@ |
|||
package com.qyft.ms.service.impl; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.qyft.ms.mapper.SysSettingsMapper; |
|||
import com.qyft.ms.model.dto.SysSettingsDTO; |
|||
import com.qyft.ms.model.entity.SysSettings; |
|||
import com.qyft.ms.model.vo.SysSettingResult; |
|||
import com.qyft.ms.model.vo.SysSettingVO; |
|||
import com.qyft.ms.service.ISysSettingsService; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 系统配置实现类 |
|||
*/ |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class ISysSettingsServiceImpl extends ServiceImpl<SysSettingsMapper, SysSettings> implements ISysSettingsService { |
|||
private final SysSettingsMapper sysSettingsMapper; |
|||
|
|||
@Override |
|||
public List<SysSettingVO> getConfig(String type) { |
|||
int parentId = sysSettingsMapper.getIdByCode(type); |
|||
return sysSettingsMapper.getConfig(String.valueOf(parentId)); |
|||
} |
|||
|
|||
@Override |
|||
public List<SysSettingResult> getAllConfig() { |
|||
List<SysSettingVO> list = sysSettingsMapper.getConfig("-1"); |
|||
List<SysSettingResult> result = new ArrayList<>(); |
|||
for (SysSettingVO sysSettings : list) { |
|||
List<SysSettingVO> childrenList = sysSettingsMapper.getConfig(String.valueOf(sysSettings.getId())); |
|||
SysSettingResult map = new SysSettingResult(); |
|||
map.setName(sysSettings.getName()); |
|||
map.setCode(sysSettings.getCode()); |
|||
map.setId(sysSettings.getId()); |
|||
map.setValue(sysSettings.getValue()); |
|||
map.setHardwareId(sysSettings.getHardwareId()); |
|||
map.setChildren(childrenList); |
|||
result.add(map); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean updateConfig(List<SysSettingsDTO> dto) { |
|||
for (SysSettingsDTO sysSettingsDTO : dto) { |
|||
sysSettingsMapper.updateById(sysSettingsDTO); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 修改服务器系统时间 |
|||
* |
|||
* @param newTime 时间字符串 YYYY-MM-DD HH:mm:ss |
|||
* @return 是否修改成功 |
|||
*/ |
|||
@Override |
|||
public boolean setSysDate(String newTime) { |
|||
try { |
|||
String command = "date -s \"" + newTime + "\""; |
|||
Process process = Runtime.getRuntime().exec(command); |
|||
int exitCode = process.waitFor(); |
|||
return exitCode == 0; |
|||
} catch (Exception e) { |
|||
log.error("修改系统时间失败", e); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,44 @@ |
|||
package com.qyft.ms.system.common.base; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.FieldFill; |
|||
import com.baomidou.mybatisplus.annotation.IdType; |
|||
import com.baomidou.mybatisplus.annotation.TableField; |
|||
import com.baomidou.mybatisplus.annotation.TableId; |
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serial; |
|||
import java.io.Serializable; |
|||
import java.time.LocalDateTime; |
|||
|
|||
/** |
|||
* 基础实体类 |
|||
* 实体类的基类,包含了实体类的公共属性,如创建时间、更新时间、逻辑删除标识等</p> |
|||
*/ |
|||
@Data |
|||
public class BaseEntity implements Serializable { |
|||
|
|||
@Serial |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
@TableId(type = IdType.AUTO) |
|||
private Long id; |
|||
|
|||
/** |
|||
* 创建时间 |
|||
*/ |
|||
@TableField(fill = FieldFill.INSERT) |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
private LocalDateTime createTime; |
|||
|
|||
/** |
|||
* 更新时间 |
|||
*/ |
|||
@TableField(fill = FieldFill.INSERT_UPDATE) |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
private LocalDateTime updateTime; |
|||
|
|||
} |
@ -0,0 +1,26 @@ |
|||
package com.qyft.ms.system.common.base; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serial; |
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* 基础分页请求对象 |
|||
*/ |
|||
@Data |
|||
@Schema |
|||
public class BasePageQuery implements Serializable { |
|||
|
|||
@Serial |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
@Schema(description = "页码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
|||
private int pageNum = 1; |
|||
|
|||
@Schema(description = "每页记录数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") |
|||
private int pageSize = 10; |
|||
|
|||
|
|||
} |
@ -0,0 +1,84 @@ |
|||
package com.qyft.ms.system.common.base; |
|||
|
|||
|
|||
import cn.hutool.core.util.ObjectUtil; |
|||
|
|||
import java.util.EnumSet; |
|||
import java.util.Objects; |
|||
|
|||
/** |
|||
* 枚举通用接口 |
|||
*/ |
|||
public interface IBaseEnum<T> { |
|||
|
|||
/** |
|||
* 根据值获取枚举 |
|||
* |
|||
* @param value |
|||
* @param clazz |
|||
* @param <E> 枚举 |
|||
* @return |
|||
*/ |
|||
static <E extends Enum<E> & IBaseEnum> E getEnumByValue(Object value, Class<E> clazz) { |
|||
Objects.requireNonNull(value); |
|||
EnumSet<E> allEnums = EnumSet.allOf(clazz); // 获取类型下的所有枚举 |
|||
E matchEnum = allEnums.stream() |
|||
.filter(e -> ObjectUtil.equal(e.getValue(), value)) |
|||
.findFirst() |
|||
.orElse(null); |
|||
return matchEnum; |
|||
} |
|||
|
|||
/** |
|||
* 根据文本标签获取值 |
|||
* |
|||
* @param value |
|||
* @param clazz |
|||
* @param <E> |
|||
* @return |
|||
*/ |
|||
static <E extends Enum<E> & IBaseEnum> String getLabelByValue(Object value, Class<E> clazz) { |
|||
Objects.requireNonNull(value); |
|||
EnumSet<E> allEnums = EnumSet.allOf(clazz); // 获取类型下的所有枚举 |
|||
E matchEnum = allEnums.stream() |
|||
.filter(e -> ObjectUtil.equal(e.getValue(), value)) |
|||
.findFirst() |
|||
.orElse(null); |
|||
|
|||
String label = null; |
|||
if (matchEnum != null) { |
|||
label = matchEnum.getLabel(); |
|||
} |
|||
return label; |
|||
} |
|||
|
|||
/** |
|||
* 根据文本标签获取值 |
|||
* |
|||
* @param label |
|||
* @param clazz |
|||
* @param <E> |
|||
* @return |
|||
*/ |
|||
static <E extends Enum<E> & IBaseEnum> Object getValueByLabel(String label, Class<E> clazz) { |
|||
Objects.requireNonNull(label); |
|||
EnumSet<E> allEnums = EnumSet.allOf(clazz); // 获取类型下的所有枚举 |
|||
String finalLabel = label; |
|||
E matchEnum = allEnums.stream() |
|||
.filter(e -> ObjectUtil.equal(e.getLabel(), finalLabel)) |
|||
.findFirst() |
|||
.orElse(null); |
|||
|
|||
Object value = null; |
|||
if (matchEnum != null) { |
|||
value = matchEnum.getValue(); |
|||
} |
|||
return value; |
|||
} |
|||
|
|||
T getValue(); |
|||
|
|||
String getLabel(); |
|||
|
|||
|
|||
} |
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue