Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
Z
zhmes-agecal
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
耿迪迪
zhmes-agecal
Commits
e9aecf8a
Commit
e9aecf8a
authored
Aug 14, 2025
by
wanghao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1 扫码绑定托盘,上料,机械臂整体测试
parent
9eb47dd7
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
506 additions
and
165 deletions
+506
-165
AgingCabinetInspectionAndPowerCheckTask.java
...ong/web/task/AgingCabinetInspectionAndPowerCheckTask.java
+150
-71
SecurityConfig.java
...main/java/com/zehong/framework/config/SecurityConfig.java
+2
-0
TEquipmentInfo.java
...rc/main/java/com/zehong/system/domain/TEquipmentInfo.java
+15
-0
TStoreyInfo.java
...m/src/main/java/com/zehong/system/domain/TStoreyInfo.java
+12
-1
TEquipmentInfoMapper.java
...n/java/com/zehong/system/mapper/TEquipmentInfoMapper.java
+2
-0
ITEquipmentInfoService.java
...ava/com/zehong/system/service/ITEquipmentInfoService.java
+2
-0
RobotArmCommandServiceImpl.java
...ehong/system/service/impl/RobotArmCommandServiceImpl.java
+6
-0
TEquipmentInfoServiceImpl.java
...zehong/system/service/impl/TEquipmentInfoServiceImpl.java
+11
-1
AgingCabinetWebSocketConfig.java
...system/service/websocket/AgingCabinetWebSocketConfig.java
+28
-0
AgingCabinetWebSocketHandler.java
...ystem/service/websocket/AgingCabinetWebSocketHandler.java
+92
-0
TEquipmentInfoMapper.xml
...src/main/resources/mapper/system/TEquipmentInfoMapper.xml
+10
-0
TStoreyInfoMapper.xml
...em/src/main/resources/mapper/system/TStoreyInfoMapper.xml
+14
-1
AgingCabinetBoard.vue
...cal-web/src/views/screen/components/AgingCabinetBoard.vue
+51
-46
AgingLayer.vue
zhmes-agecal-web/src/views/screen/components/AgingLayer.vue
+109
-43
RoboticArm.vue
zhmes-agecal-web/src/views/screen/components/RoboticArm.vue
+2
-2
No files found.
zhmes-agecal-admin/src/main/java/com/zehong/web/task/AgingCabinetInspectionAndPowerCheckTask.java
View file @
e9aecf8a
package
com
.
zehong
.
web
.
task
;
import
com.serotonin.modbus4j.ModbusMaster
;
import
com.serotonin.modbus4j.exception.ErrorResponseException
;
import
com.serotonin.modbus4j.exception.ModbusInitException
;
import
com.serotonin.modbus4j.exception.ModbusTransportException
;
import
com.zehong.system.domain.TEquipmentAlarmData
;
import
com.zehong.system.domain.TEquipmentInfo
;
import
com.zehong.system.domain.modbus.ModbusDeviceData
;
import
com.zehong.system.modbus.util.Modbus4jUtils
;
import
com.zehong.system.service.ITEquipmentAlarmDataService
;
import
com.zehong.system.service.ITEquipmentInfoService
;
import
com.zehong.system.service.websocket.AgingCabinetWebSocketHandler
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.context.ApplicationEventPublisher
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.context.request.async.DeferredResult
;
import
javax.annotation.Resource
;
import
java.util.*
;
import
java.util.concurrent.CompletableFuture
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.stream.Collectors
;
/**
* @author lenovo
...
...
@@ -25,6 +37,15 @@ public class AgingCabinetInspectionAndPowerCheckTask {
@Resource
private
ITEquipmentInfoService
tEquipmentInfoService
;
@Resource
private
ApplicationEventPublisher
eventPublisher
;
// 新增事件发布器
@Resource
private
ITEquipmentAlarmDataService
tEquipmentAlarmDataService
;
@Resource
private
AgingCabinetWebSocketHandler
agingCabinetWebSocketHandler
;
/**
* 五分钟一次
* 1.老化柜、标定柜巡查
...
...
@@ -52,77 +73,135 @@ public class AgingCabinetInspectionAndPowerCheckTask {
type
.
add
(
"2"
);
List
<
TEquipmentInfo
>
equipmentInfos
=
tEquipmentInfoService
.
selectTEquipmentList
(
type
);
// try {
// if (equipmentInfos.size() == 0) {
// log.error("设备列表查询结果为空");
// throw new Exception("无设备信息!");
// }
//
// // 10 层
// List<Integer> registerOffset = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
//
// List<CompletableFuture<ModbusDeviceData>> futures = equipmentInfos.stream().map(equipmentInfo -> CompletableFuture.supplyAsync(() -> {
// ModbusMaster master = null;
// try {
// master = Modbus4jUtils.getMaster(equipmentInfo.getfIp(), equipmentInfo.getfPort());
// Map<Integer, Object> integerObjectMap = Modbus4jUtils.batchReadAgingCabinetStatus(master, registerOffset);
// // 构造结果对象
// ModbusDeviceData deviceData = new ModbusDeviceData();
// deviceData.setDeviceCode(equipmentInfo.getfEquipmentCode());
// deviceData.setRegisterValues(integerObjectMap.entrySet().stream()
// .collect(Collectors.toMap(
// Map.Entry::getKey,
// e -> e.getValue() != null ? e.getValue().toString() : "NULL"
// )));
//
// return deviceData;
//
// } catch (ModbusInitException e) {
//
// // 初始化失败
// Map<Integer, String> errorMap = new HashMap<>();
//
// ModbusDeviceData deviceData = new ModbusDeviceData();
// deviceData.setDeviceCode("");
// deviceData.setRegisterValues(errorMap);
//
// return deviceData;
// } catch (ModbusTransportException | ErrorResponseException e) {
// // 返回错误信息
// Map<Integer, String> errorMap = new HashMap<>();
// registerOffset.forEach(offset -> errorMap.put(offset, "ERROR: " + e.getMessage()));
//
// ModbusDeviceData deviceData = new ModbusDeviceData();
// deviceData.setDeviceCode(equipmentInfo.getfEquipmentCode());
// deviceData.setRegisterValues(errorMap);
//
// return deviceData;
// } finally {
// if (master != null) {
// master.destroy();
// }
// }
// }, executor)).collect(Collectors.toList());
//
// // 等待所有任务完成并收集结果
// CompletableFuture<List<ModbusDeviceData>> listCompletableFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
// .thenApply(v -> futures.stream()
// .map(CompletableFuture::join)
// .collect(Collectors.toList()));
//
// DeferredResult<List<ModbusDeviceData>> deferredResult = new DeferredResult<>();
//
// listCompletableFuture.whenComplete((result, ex) -> {
// if (ex != null) {
// deferredResult.setErrorResult(Collections.singletonList(createErrorData(ex)));
// } else {
// deferredResult.setResult(result);
// }
// });
//
// } catch (Exception e) {
// e.printStackTrace();
// }
TEquipmentAlarmData
alarmData
=
new
TEquipmentAlarmData
();
try
{
if
(
equipmentInfos
.
size
()
==
0
)
{
log
.
error
(
"设备列表查询结果为空"
);
return
;
}
List
<
CompletableFuture
<
TEquipmentInfo
>>
futures
=
equipmentInfos
.
stream
().
map
(
equipmentInfo
->
CompletableFuture
.
supplyAsync
(()
->
{
ModbusMaster
master
=
null
;
// 10 层
List
<
Integer
>
registerOffsets
=
Arrays
.
asList
(
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
);
try
{
master
=
Modbus4jUtils
.
getMaster
(
equipmentInfo
.
getfIp
(),
equipmentInfo
.
getfPort
());
Map
<
Integer
,
Object
>
integerObjectMap
=
Modbus4jUtils
.
batchReadAgingCabinetStatus
(
master
,
registerOffsets
);
equipmentInfo
.
setRegisterValues
(
integerObjectMap
);
}
catch
(
ModbusInitException
e
)
{
// 记录异常数据
alarmData
.
setfAlarmType
(
"01"
);
//01.老化柜 02.机械臂 03.老化层 04.点位
alarmData
.
setfEquipmentCode
(
equipmentInfo
.
getfEquipmentCode
());
alarmData
.
setfAlarmData
(
"定时任务巡检:Modbus初始化失败"
);
tEquipmentAlarmDataService
.
insertTEquipmentAlarmData
(
alarmData
);
// 更新老化柜状态(“0”空闲,“1”运行,“2”故障)
equipmentInfo
.
setfStatus
(
"2"
);
equipmentInfo
.
setErrorReason
(
"定时任务巡检:Modbus初始化失败"
);
equipmentInfo
.
setRegisterValues
(
new
HashMap
<>());
// 返回结果
return
equipmentInfo
;
// 层有错误返回 柜可能连不上也在这个报错里面
}
catch
(
ModbusTransportException
e
)
{
// 网线没插好通讯不上
if
(
e
.
getMessage
().
equals
(
"java.net.SocketTimeoutException: connect timed out"
))
{
// 记录异常数据
alarmData
.
setfAlarmType
(
"01"
);
//01.老化柜 02.机械臂 03.老化层 04.点位
alarmData
.
setfEquipmentCode
(
equipmentInfo
.
getfEquipmentCode
());
alarmData
.
setfAlarmData
(
"定时任务巡检:老化柜网线没插好"
);
equipmentInfo
.
setErrorReason
(
"定时任务巡检:老化柜网线没插好"
);
// 线接错误
}
else
{
// 记录异常数据
alarmData
.
setfAlarmType
(
"01"
);
//01.老化柜 02.机械臂 03.老化层 04.点位
alarmData
.
setfEquipmentCode
(
equipmentInfo
.
getfEquipmentCode
());
alarmData
.
setfAlarmData
(
"定时任务巡检:老化柜通信线路没接好"
);
equipmentInfo
.
setErrorReason
(
"定时任务巡检:老化柜通信线路没接好"
);
}
tEquipmentAlarmDataService
.
insertTEquipmentAlarmData
(
alarmData
);
// 更新老化柜状态(“0”空闲,“1”运行,“2”故障)
equipmentInfo
.
setRegisterValues
(
new
HashMap
<>());
equipmentInfo
.
setfStatus
(
"2"
);
return
equipmentInfo
;
}
catch
(
ErrorResponseException
e
)
{
equipmentInfo
.
setfStatus
(
"2"
);
equipmentInfo
.
setRegisterValues
(
new
HashMap
<>());
equipmentInfo
.
setErrorReason
(
"定时任务巡检:ErrorResponseException"
);
return
equipmentInfo
;
}
finally
{
if
(
master
!=
null
)
{
master
.
destroy
();
}
}
return
equipmentInfo
;
},
executor
)).
collect
(
Collectors
.
toList
());
// 等待所有任务完成并收集结果
CompletableFuture
<
List
<
TEquipmentInfo
>>
listCompletableFuture
=
CompletableFuture
.
allOf
(
futures
.
toArray
(
new
CompletableFuture
[
0
]))
.
thenApply
(
v
->
futures
.
stream
()
.
map
(
CompletableFuture:
:
join
)
.
collect
(
Collectors
.
toList
()));
// 处理 老化柜 是 运行 开始 空闲
CompletableFuture
<
List
<
TEquipmentInfo
>>
processedFuture
=
listCompletableFuture
.
thenApply
(
this
::
processDeviceData
);
processedFuture
.
whenComplete
((
result
,
ex
)
->
{
tEquipmentInfoService
.
batchUpdate
(
result
);
// 执行WebSocket广播,推送最新老化柜状态
if
(
result
!=
null
&&
!
result
.
isEmpty
())
{
agingCabinetWebSocketHandler
.
broadcastAgingCabinetData
(
result
);
log
.
info
(
"已通过WebSocket广播{}条老化柜状态数据"
,
result
.
size
());
}
});
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
// 处理 老化柜 是 运行 开始 空闲
private
List
<
TEquipmentInfo
>
processDeviceData
(
List
<
TEquipmentInfo
>
deviceDataList
)
{
for
(
TEquipmentInfo
modbusDeviceData
:
deviceDataList
)
{
Map
<
Integer
,
Object
>
registerValues
=
modbusDeviceData
.
getRegisterValues
();
// 大于0 说明 柜能通信;小于0 说明柜 不能通信
if
(
registerValues
.
size
()
>
0
)
{
boolean
isRun
=
false
;
for
(
Map
.
Entry
<
Integer
,
Object
>
entry
:
registerValues
.
entrySet
())
{
Integer
registerOffset
=
entry
.
getKey
();
Object
registerValue
=
entry
.
getValue
();
if
(
"true"
.
equals
(
registerValue
))
{
eventPublisher
.
publishEvent
(
new
CheckPowerOnCommandEvent
(
this
,
modbusDeviceData
.
getfEquipmentCode
(),
modbusDeviceData
.
getfPowerOutageIp
(),
modbusDeviceData
.
getfPowerOutagePort
(),
registerOffset
));
isRun
=
true
;
// 要给这个 层 发断电的 指令
}
else
{
// 发布断电指令事件(不再直接执行)
eventPublisher
.
publishEvent
(
new
PowerOffCommandEvent
(
this
,
modbusDeviceData
.
getfEquipmentCode
(),
modbusDeviceData
.
getfPowerOutageIp
(),
modbusDeviceData
.
getfPowerOutagePort
(),
registerOffset
));
}
}
if
(
isRun
)
{
modbusDeviceData
.
setfStatus
(
"1"
);
}
else
{
modbusDeviceData
.
setfStatus
(
"0"
);
}
}
else
{
modbusDeviceData
.
setfStatus
(
"0"
);
}
}
return
deviceDataList
;
}
private
ModbusDeviceData
createErrorData
(
Throwable
ex
)
{
...
...
zhmes-agecal-framework/src/main/java/com/zehong/framework/config/SecurityConfig.java
View file @
e9aecf8a
...
...
@@ -108,6 +108,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
// 对于 websocket 匿名访问
.
antMatchers
(
"/ws-robot-arm"
).
permitAll
()
// 对于 websocket 匿名访问
.
antMatchers
(
"/ws-aging-cabinet"
).
permitAll
()
.
antMatchers
(
"/profile/**"
).
anonymous
()
.
antMatchers
(
"/common/download**"
).
anonymous
()
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/domain/TEquipmentInfo.java
View file @
e9aecf8a
package
com
.
zehong
.
system
.
domain
;
import
java.util.Date
;
import
java.util.Map
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
org.apache.commons.lang3.builder.ToStringBuilder
;
import
org.apache.commons.lang3.builder.ToStringStyle
;
...
...
@@ -78,6 +80,11 @@ public class TEquipmentInfo extends BaseEntity
@Excel
(
name
=
"状态:0空闲,1运行,2故障"
)
private
String
fStatus
;
/**
* 寄存器值
*/
private
Map
<
Integer
,
Object
>
registerValues
;
/**
* 故障原因
*/
...
...
@@ -263,6 +270,14 @@ public class TEquipmentInfo extends BaseEntity
this
.
errorReason
=
errorReason
;
}
public
Map
<
Integer
,
Object
>
getRegisterValues
()
{
return
registerValues
;
}
public
void
setRegisterValues
(
Map
<
Integer
,
Object
>
registerValues
)
{
this
.
registerValues
=
registerValues
;
}
@Override
public
String
toString
()
{
return
new
ToStringBuilder
(
this
,
ToStringStyle
.
MULTI_LINE_STYLE
)
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/domain/TStoreyInfo.java
View file @
e9aecf8a
...
...
@@ -39,6 +39,9 @@ public class TStoreyInfo extends BaseEntity
@Excel
(
name
=
"层编号"
)
private
String
fStoreyCode
;
/** 托盘编号 */
private
String
fTrayCode
;
/** IP地址 */
@Excel
(
name
=
"IP地址"
)
private
String
fIp
;
...
...
@@ -79,6 +82,14 @@ public class TStoreyInfo extends BaseEntity
@Excel
(
name
=
"报警时间"
,
width
=
30
,
dateFormat
=
"yyyy-MM-dd"
)
private
Date
fAlarmTime
;
public
String
getfTrayCode
()
{
return
fTrayCode
;
}
public
void
setfTrayCode
(
String
fTrayCode
)
{
this
.
fTrayCode
=
fTrayCode
;
}
public
void
setfStoreyId
(
Long
fStoreyId
)
{
this
.
fStoreyId
=
fStoreyId
;
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/mapper/TEquipmentInfoMapper.java
View file @
e9aecf8a
...
...
@@ -52,6 +52,8 @@ public interface TEquipmentInfoMapper
*/
public
int
updateTEquipmentInfo
(
TEquipmentInfo
tEquipmentInfo
);
public
int
batchUpdate
(
@Param
(
"equipmentInfos"
)
List
<
TEquipmentInfo
>
equipmentInfos
);
/**
* 删除生产设备信息
*
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/service/ITEquipmentInfoService.java
View file @
e9aecf8a
...
...
@@ -58,6 +58,8 @@ public interface ITEquipmentInfoService
*/
public
int
updateTEquipmentInfo
(
TEquipmentInfo
tEquipmentInfo
);
public
int
batchUpdate
(
List
<
TEquipmentInfo
>
equipmentInfos
);
/**
* 批量删除生产设备信息
*
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/service/impl/RobotArmCommandServiceImpl.java
View file @
e9aecf8a
...
...
@@ -79,6 +79,8 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
if
(!
loadingCommands
.
isEmpty
())
{
boolean
[]
roboticArmEntryConveyorData
=
Modbus4jUtils
.
getRoboticArmEntryConveyorData
();
log
.
info
(
"机械臂入口 conveyor 0状态: "
+
roboticArmEntryConveyorData
[
0
]);
log
.
info
(
"机械臂入口 conveyor 1状态: "
+
roboticArmEntryConveyorData
[
1
]);
if
(
roboticArmEntryConveyorData
[
1
])
{
sendCommand
(
loadingCommands
.
get
(
0
),
"LOAD"
);
return
;
...
...
@@ -221,6 +223,10 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
if
(
tStoreyInfo
!=
null
)
{
robotArmCommand
.
setStatus
(
"1"
);
robotArmCommand
.
setStoreyCode
(
tStoreyInfo
.
getfStoreyCode
());
tTrayInfo
.
setfStoreyCode
(
tStoreyInfo
.
getfStoreyCode
());
tTrayInfo
.
setfBindingTime
(
new
Date
());
tTrayInfoMapper
.
updateTTrayInfo
(
tTrayInfo
);
}
else
{
robotArmCommand
.
setStoreyCode
(
"待分配位置"
);
}
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/service/impl/TEquipmentInfoServiceImpl.java
View file @
e9aecf8a
...
...
@@ -4,7 +4,6 @@ import java.util.ArrayList;
import
java.util.List
;
import
java.util.concurrent.CompletableFuture
;
import
com.sun.org.apache.xpath.internal.operations.Mod
;
import
com.zehong.system.domain.modbus.ModbusDeviceData
;
import
org.springframework.stereotype.Service
;
import
com.zehong.system.mapper.TEquipmentInfoMapper
;
...
...
@@ -91,6 +90,17 @@ public class TEquipmentInfoServiceImpl implements ITEquipmentInfoService
return
tEquipmentInfoMapper
.
updateTEquipmentInfo
(
tEquipmentInfo
);
}
/**
* 批量修改生产设备信息
*
* @param equipmentInfos 生产设备信息集合
* @return 结果
*/
@Override
public
int
batchUpdate
(
List
<
TEquipmentInfo
>
equipmentInfos
)
{
return
0
;
}
/**
* 批量删除生产设备信息
*
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/service/websocket/AgingCabinetWebSocketConfig.java
0 → 100644
View file @
e9aecf8a
package
com
.
zehong
.
system
.
service
.
websocket
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.socket.config.annotation.EnableWebSocket
;
import
org.springframework.web.socket.config.annotation.WebSocketConfigurer
;
import
org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry
;
import
javax.annotation.Resource
;
/**
* @author lenovo
* @date 2025/8/14
* @description 老化柜WebSocket配置类
*/
@Configuration
@EnableWebSocket
public
class
AgingCabinetWebSocketConfig
implements
WebSocketConfigurer
{
@Resource
private
AgingCabinetWebSocketHandler
agingCabinetWebSocketHandler
;
@Override
public
void
registerWebSocketHandlers
(
WebSocketHandlerRegistry
registry
)
{
// 注册处理器,设置访问路径为/ws-aging-cabinet,允许所有跨域
registry
.
addHandler
(
agingCabinetWebSocketHandler
,
"/ws-aging-cabinet"
)
.
setAllowedOrigins
(
"*"
);
}
}
\ No newline at end of file
zhmes-agecal-system/src/main/java/com/zehong/system/service/websocket/AgingCabinetWebSocketHandler.java
0 → 100644
View file @
e9aecf8a
package
com
.
zehong
.
system
.
service
.
websocket
;
import
org.springframework.stereotype.Component
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.zehong.system.domain.TEquipmentInfo
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.web.socket.CloseStatus
;
import
org.springframework.web.socket.TextMessage
;
import
org.springframework.web.socket.WebSocketSession
;
import
org.springframework.web.socket.handler.TextWebSocketHandler
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.CopyOnWriteArrayList
;
/**
* @author lenovo
* @date 2025/8/14
* @description 老化柜WebSocket处理器
*/
@Component
public
class
AgingCabinetWebSocketHandler
extends
TextWebSocketHandler
{
// 线程安全的会话列表,存储所有连接的客户端
private
static
final
List
<
WebSocketSession
>
sessions
=
new
CopyOnWriteArrayList
<>();
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
AgingCabinetWebSocketHandler
.
class
);
/**
* 连接建立后添加会话
*/
@Override
public
void
afterConnectionEstablished
(
WebSocketSession
session
)
throws
Exception
{
sessions
.
add
(
session
);
log
.
info
(
"新的老化柜WebSocket连接建立,当前连接数: {}"
,
sessions
.
size
());
}
/**
* 连接关闭后移除会话
*/
@Override
public
void
afterConnectionClosed
(
WebSocketSession
session
,
CloseStatus
status
)
{
sessions
.
remove
(
session
);
log
.
info
(
"老化柜WebSocket连接关闭,当前连接数: {}"
,
sessions
.
size
());
}
/**
* 广播老化柜数据给所有客户端
* @param equipmentList 处理后的老化柜设备列表
*/
public
void
broadcastAgingCabinetData
(
List
<
TEquipmentInfo
>
equipmentList
)
{
try
{
String
message
=
createAgingCabinetMessage
(
equipmentList
);
for
(
WebSocketSession
session
:
sessions
)
{
if
(
session
.
isOpen
())
{
session
.
sendMessage
(
new
TextMessage
(
message
));
}
}
}
catch
(
IOException
e
)
{
log
.
error
(
"广播老化柜数据失败"
,
e
);
}
}
/**
* 构建老化柜数据消息
* 转换为前端需要的格式(与cabinetRows所需字段匹配)
*/
private
String
createAgingCabinetMessage
(
List
<
TEquipmentInfo
>
equipmentList
)
throws
JsonProcessingException
{
ObjectMapper
mapper
=
new
ObjectMapper
();
List
<
Map
<
String
,
Object
>>
cabinetData
=
new
ArrayList
<>();
for
(
TEquipmentInfo
equipment
:
equipmentList
)
{
Map
<
String
,
Object
>
dataMap
=
new
HashMap
<>();
// 前端需要的核心字段
dataMap
.
put
(
"fEquipmentId"
,
equipment
.
getfEquipmentId
());
dataMap
.
put
(
"fEquipmentCode"
,
equipment
.
getfEquipmentCode
());
dataMap
.
put
(
"fStatus"
,
equipment
.
getfStatus
());
dataMap
.
put
(
"errorReason"
,
equipment
.
getErrorReason
());
dataMap
.
put
(
"registerValues"
,
equipment
.
getRegisterValues
());
// 可选:层状态数据
cabinetData
.
add
(
dataMap
);
}
Map
<
String
,
Object
>
message
=
new
HashMap
<>();
message
.
put
(
"type"
,
"aging_cabinet_data"
);
// 消息类型标识
message
.
put
(
"data"
,
cabinetData
);
return
mapper
.
writeValueAsString
(
message
);
}
}
\ No newline at end of file
zhmes-agecal-system/src/main/resources/mapper/system/TEquipmentInfoMapper.xml
View file @
e9aecf8a
...
...
@@ -129,6 +129,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</trim>
where f_equipment_id = #{fEquipmentId}
</update>
<update
id=
"batchUpdate"
parameterType=
"list"
>
<foreach
collection=
"equipmentInfos"
item=
"item"
index=
"index"
separator=
";"
>
update t_equipment_info
<trim
prefix=
"SET"
suffixOverrides=
","
>
<if
test=
"item.fStatus != null"
>
f_status = #{item.fStatus},
</if>
<if
test=
"item.errorReason != null"
>
f_error_Reason = #{item.errorReason},
</if>
</trim>
where f_equipment_id = #{item.fEquipmentId}
</foreach>
</update>
<delete
id=
"deleteTEquipmentInfoById"
parameterType=
"Long"
>
delete from t_equipment_info where f_equipment_id = #{fEquipmentId}
...
...
zhmes-agecal-system/src/main/resources/mapper/system/TStoreyInfoMapper.xml
View file @
e9aecf8a
...
...
@@ -8,6 +8,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result
property=
"fStoreyId"
column=
"f_storey_id"
/>
<result
property=
"fEquipmentId"
column=
"f_equipment_id"
/>
<result
property=
"fStoreyCode"
column=
"f_storey_code"
/>
<result
property=
"fTrayCode"
column=
"f_tray_code"
/>
<result
property=
"fIp"
column=
"f_ip"
/>
<result
property=
"fStatus"
column=
"f_status"
/>
<result
property=
"fPort"
column=
"f_port"
/>
...
...
@@ -18,7 +19,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql
id=
"selectTStoreyInfoVo"
>
select f_storey_id, f_equipment_id, f_storey_code, f_ip, f_status, f_port, f_aging_start_time, f_update_time, f_create_time, f_alarm_time from t_storey_info
select storeyInfo.f_storey_id,
storeyInfo.f_equipment_id,
storeyInfo.f_storey_code,
storeyInfo.f_ip,
storeyInfo.f_status,
storeyInfo.f_port,
storeyInfo.f_aging_start_time,
storeyInfo.f_update_time,
storeyInfo.f_create_time,
storeyInfo.f_alarm_time,
trayInfo.f_tray_code
from t_storey_info storeyInfo
left join t_tray_info trayInfo on storeyInfo.f_storey_code = trayInfo.f_storey_code
</sql>
<select
id=
"selectTStoreyInfoList"
parameterType=
"TStoreyInfo"
resultMap=
"TStoreyInfoResult"
>
...
...
zhmes-agecal-web/src/views/screen/components/AgingCabinetBoard.vue
View file @
e9aecf8a
...
...
@@ -56,7 +56,7 @@
font-weight: bold;"
@
click
.
native=
"handleCardClick(item)"
>
{{
item
.
fEquipment
Id
+
"号柜"
}}
{{
item
.
fEquipment
Code
+
"号柜"
}}
</el-card>
</el-tooltip>
</el-col>
...
...
@@ -68,52 +68,13 @@
</
template
>
<
script
>
import
{
getAgingCabinetAndPowerCheck
}
from
"@/api/testScheduledTasks/testTasks"
;
import
{
getAllEquipmentList
}
from
"@/api/equipment/equipment"
export
default
{
name
:
"AgingCabinetBoard"
,
data
()
{
return
{
// 示例数据格式,实际从后端获取
cabinets
:
[
// { id: 1, deviceStatus: '1' },
// { id: 2, deviceStatus: '2' },
// { id: 3, deviceStatus: '0' },
// { id: 4, deviceStatus: '0' },
// { id: 5, deviceStatus: '0' },
// { id: 6, deviceStatus: '0' },
// { id: 7, deviceStatus: '0' },
// { id: 8, deviceStatus: '0' },
// { id: 9, deviceStatus: '0' },
// { id: 10, deviceStatus: '0' },
// { id: 11, deviceStatus: '0' },
// { id: 12, deviceStatus: '0' },
// { id: 13, deviceStatus: '0' },
// { id: 14, deviceStatus: '0' },
// { id: 15, deviceStatus: '0' },
// { id: 16, deviceStatus: '0' },
// { id: 17, deviceStatus: '0' },
// { id: 18, deviceStatus: '0' },
// { id: 19, deviceStatus: '0' },
// { id: 20, deviceStatus: '0' },
// { id: 21, deviceStatus: '0' },
// { id: 22, deviceStatus: '0' },
// { id: 23, deviceStatus: '0' },
// { id: 24, deviceStatus: '0' },
// { id: 25, deviceStatus: '0' },
// { id: 26, deviceStatus: '0' },
// { id: 27, deviceStatus: '0' },
// { id: 28, deviceStatus: '0' },
// { id: 29, deviceStatus: '0' },
// { id: 30, deviceStatus: '0' },
// { id: 31, deviceStatus: '0' },
// { id: 32, deviceStatus: '0' },
// { id: 33, deviceStatus: '0' },
// { id: 34, deviceStatus: '0' },
// { id: 35, deviceStatus: '0' },
// { id: 36, deviceStatus: '0' },
// 共36个
],
cabinets
:
[],
// 状态对应的颜色类名
statusMap
:
{
0
:
'default'
,
...
...
@@ -138,8 +99,50 @@ export default {
},
mounted
()
{
this
.
testAgingCabinetAndPowerCheck
();
this
.
initWebSocket
();
// 初始化WebSocket连接
},
methods
:
{
// 初始化WebSocket连接
initWebSocket
()
{
// 根据当前页面协议选择ws/wss
const
backendUrl
=
process
.
env
.
VUE_APP_API_BASE_URL
||
'http://localhost:8080'
;
const
wsUrl
=
backendUrl
.
replace
(
'http'
,
'ws'
)
+
'/ws-aging-cabinet'
;
this
.
ws
=
new
WebSocket
(
wsUrl
);
// 连接建立
this
.
ws
.
onopen
=
()
=>
{
console
.
log
(
'老化柜WebSocket连接已建立'
);
this
.
pageLoading
=
false
;
};
// 接收消息
this
.
ws
.
onmessage
=
(
event
)
=>
{
try
{
const
message
=
JSON
.
parse
(
event
.
data
);
// 只处理老化柜数据类型的消息
if
(
message
.
type
===
'aging_cabinet_data'
)
{
this
.
cabinets
=
message
.
data
;
// 更新数据,自动触发cabinetRows重新计算
console
.
log
(
'收到老化柜更新数据,共'
,
message
.
data
.
length
,
'条'
);
}
}
catch
(
e
)
{
console
.
error
(
'解析WebSocket消息失败'
,
e
);
}
};
// 连接关闭(自动重连)
this
.
ws
.
onclose
=
()
=>
{
console
.
log
(
'老化柜WebSocket连接关闭,3秒后尝试重连'
);
setTimeout
(()
=>
this
.
initWebSocket
(),
3000
);
};
// 连接错误
this
.
ws
.
onerror
=
(
error
)
=>
{
console
.
error
(
'老化柜WebSocket错误'
,
error
);
this
.
pageLoading
=
false
;
};
},
handleCardClick
(
item
)
{
// 触发事件传递 cabinetId 给父组件
// 3 是 AgingLayer 组件的索引
...
...
@@ -159,15 +162,17 @@ export default {
testAgingCabinetAndPowerCheck
()
{
// 开始加载:显示全局loading
this
.
pageLoading
=
true
;
// getAgingCabinetAndPowerCheck().then(response => {
// this.cabinets = response;
// this.pageLoading = false;
// });
getAllEquipmentList
().
then
(
response
=>
{
this
.
cabinets
=
response
;
this
.
pageLoading
=
false
;
})
},
// 组件销毁时关闭WebSocket连接
beforeDestroy
()
{
if
(
this
.
ws
)
{
this
.
ws
.
close
();
this
.
ws
=
null
;
}
}
}
};
...
...
zhmes-agecal-web/src/views/screen/components/AgingLayer.vue
View file @
e9aecf8a
...
...
@@ -5,7 +5,7 @@
<!-- 头部标题区域 -->
<div
class=
"tray-header"
>
<div
class=
"tray-title"
>
<div
class=
"title-text"
>
{{
modbusDeviceData
.
id
}}
号柜
</div>
<div
class=
"title-text"
>
{{
modbusDeviceData
.
fEquipmentCode
}}
号柜
</div>
<div
class=
"title-line"
></div>
</div>
</div>
...
...
@@ -30,7 +30,12 @@
:class=
"[
'layer-depth',
`layer-$
{index}`,
getStatusClass(layer.fStatus) // 动态状态类
{
'status-running': layer.fStatus === '1',
'status-fault': layer.fStatus === '2',
'status-idle': layer.fStatus === '0',
'status-power_outage': layer.fStatus === '3'
}
]"
@click="selectLayer(index)"
>
...
...
@@ -51,18 +56,14 @@
<!-- 托盘信息展示区域 -->
<div
class=
"tray-header-inner"
>
<span
class=
"tray-label"
>
托盘
</span>
<span
class=
"tray-id"
>
{{
modbusDeviceData
.
fTrayCode
}}
</span>
<span
class=
"tray-id"
>
{{
trayInfo
.
fTrayCode
}}
</span>
</div>
<div
class=
"tray-info"
>
<div
class=
"info-row"
>
<div
class=
"info-label"
>
所在柜体:
</div>
<div
class=
"info-value"
>
{{
modbusDeviceData
.
id
}}
号柜 -
{{
trayInfo
.
layer
.
split
(
"-"
)[
1
]
||
'--'
}}
层
</div>
<div
class=
"info-value"
>
{{
modbusDeviceData
.
fEquipmentCode
}}
号柜 -
{{
trayInfo
.
layer
?
trayInfo
.
layer
.
split
(
"-"
)[
1
]
:
'--'
}}
层
</div>
</div>
<!--
<div
class=
"info-row"
>
-->
<!--
<div
class=
"info-label"
>
产品型号:
</div>
-->
<!--
<div
class=
"info-value"
>
{{
trayInfo
.
productModel
||
'--'
}}
</div>
-->
<!--
</div>
-->
<div
class=
"info-row"
>
<div
class=
"info-label"
>
当前状态:
</div>
<div
class=
"info-value"
:class=
"trayInfo.statusClass || 'status-idle'"
>
...
...
@@ -136,8 +137,8 @@ export default {
}
},
mounted
()
{
if
(
this
.
modbusDeviceData
&&
this
.
modbusDeviceData
.
i
d
)
{
this
.
loadCabinetData
(
this
.
modbusDeviceData
.
i
d
);
if
(
this
.
modbusDeviceData
&&
this
.
modbusDeviceData
.
fEquipmentI
d
)
{
this
.
loadCabinetData
(
this
.
modbusDeviceData
.
fEquipmentI
d
);
}
},
beforeDestroy
()
{
...
...
@@ -331,27 +332,107 @@ export default {
border-radius
:
2px
;
}
/* 状态背景色 */
.status-idle
{
background
:
linear-gradient
(
to
bottom
,
rgba
(
255
,
255
,
255
,
0.15
),
rgba
(
0
,
0
,
0
,
0.2
));
border-color
:
rgba
(
240
,
240
,
240
,
1
)
!important
;
/* 层状态样式 - 运行中 */
.status-running
{
/* 运行中状态 - 绿色 #67c23a */
color
:
#67c23a
;
border
:
1px
solid
rgba
(
103
,
194
,
58
,
0.8
);
box-shadow
:
0
4px
12px
rgba
(
0
,
0
,
0
,
0.6
),
inset
0
0
8px
rgba
(
103
,
194
,
58
,
0.5
);
}
.status-running.layer-depth
{
border-width
:
1px
3px
3px
1px
;
border-color
:
rgba
(
103
,
194
,
58
,
0.4
)
rgba
(
103
,
194
,
58
,
0.8
)
rgba
(
103
,
194
,
58
,
0.8
)
rgba
(
103
,
194
,
58
,
0.4
);
}
.status-running
{
background
:
linear-gradient
(
to
bottom
,
rgba
(
100
,
255
,
100
,
0.15
),
rgba
(
0
,
80
,
0
,
0.2
))
!important
;
border-color
:
rgba
(
100
,
255
,
100
,
0.8
)
!important
;
.status-running
:hover
{
background
:
linear-gradient
(
to
bottom
,
rgba
(
103
,
194
,
58
,
0.2
),
rgba
(
0
,
0
,
0
,
0.3
));
box-shadow
:
0
4px
15px
rgba
(
103
,
194
,
58
,
0.4
),
inset
0
0
10px
rgba
(
103
,
194
,
58
,
0.4
);
}
/* 层状态样式 - 故障 */
.status-fault
{
background
:
linear-gradient
(
to
bottom
,
rgba
(
255
,
100
,
100
,
0.15
),
rgba
(
80
,
0
,
0
,
0.2
))
!important
;
border-color
:
rgba
(
255
,
100
,
100
,
0.8
)
!important
;
/* 故障状态 - 红色 #f56c6c */
color
:
#f56c6c
;
border
:
1px
solid
rgba
(
245
,
108
,
108
,
0.8
);
box-shadow
:
0
4px
12px
rgba
(
0
,
0
,
0
,
0.6
),
inset
0
0
8px
rgba
(
245
,
108
,
108
,
0.5
);
}
.status-fault.layer-depth
{
border-width
:
1px
3px
3px
1px
;
border-color
:
rgba
(
245
,
108
,
108
,
0.4
)
rgba
(
245
,
108
,
108
,
0.8
)
rgba
(
245
,
108
,
108
,
0.8
)
rgba
(
245
,
108
,
108
,
0.4
);
}
.status-fault
:hover
{
background
:
linear-gradient
(
to
bottom
,
rgba
(
245
,
108
,
108
,
0.2
),
rgba
(
0
,
0
,
0
,
0.3
));
box-shadow
:
0
4px
15px
rgba
(
245
,
108
,
108
,
0.4
),
inset
0
0
10px
rgba
(
245
,
108
,
108
,
0.4
);
}
/* 层状态样式 - 空闲 */
.status-idle
{
/* 空闲状态 - 浅灰 #f0f0f0 */
color
:
#f0f0f0
;
border
:
1px
solid
rgba
(
240
,
240
,
240
,
0.8
);
box-shadow
:
0
4px
12px
rgba
(
0
,
0
,
0
,
0.6
),
inset
0
0
8px
rgba
(
240
,
240
,
240
,
0.5
);
}
.status-idle.layer-depth
{
border-width
:
1px
3px
3px
1px
;
border-color
:
rgba
(
240
,
240
,
240
,
0.4
)
rgba
(
240
,
240
,
240
,
0.8
)
rgba
(
240
,
240
,
240
,
0.8
)
rgba
(
240
,
240
,
240
,
0.4
);
}
.status-idle
:hover
{
background
:
linear-gradient
(
to
bottom
,
rgba
(
240
,
240
,
240
,
0.2
),
rgba
(
0
,
0
,
0
,
0.3
));
box-shadow
:
0
4px
15px
rgba
(
240
,
240
,
240
,
0.4
),
inset
0
0
10px
rgba
(
240
,
240
,
240
,
0.4
);
}
/* 层状态样式 - 断电 */
.status-power_outage
{
background
:
linear-gradient
(
to
bottom
,
rgba
(
150
,
150
,
150
,
0.15
),
rgba
(
50
,
50
,
50
,
0.2
))
!important
;
border-color
:
rgba
(
150
,
150
,
150
,
0.8
)
!important
;
color
:
#9e9e9e
;
border
:
1px
solid
rgba
(
158
,
158
,
158
,
0.8
);
box-shadow
:
0
4px
12px
rgba
(
0
,
0
,
0
,
0.6
),
inset
0
0
8px
rgba
(
158
,
158
,
158
,
0.5
);
}
.status-power_outage.layer-depth
{
border-width
:
1px
3px
3px
1px
;
border-color
:
rgba
(
158
,
158
,
158
,
0.4
)
rgba
(
158
,
158
,
158
,
0.8
)
rgba
(
158
,
158
,
158
,
0.8
)
rgba
(
158
,
158
,
158
,
0.4
);
}
.status-power_outage
:hover
{
background
:
linear-gradient
(
to
bottom
,
rgba
(
158
,
158
,
158
,
0.2
),
rgba
(
0
,
0
,
0
,
0.3
));
box-shadow
:
0
4px
15px
rgba
(
158
,
158
,
158
,
0.4
),
inset
0
0
10px
rgba
(
158
,
158
,
158
,
0.4
);
}
/* 层内容样式 */
...
...
@@ -368,11 +449,13 @@ export default {
font-size
:
16px
;
font-weight
:
bold
;
margin-bottom
:
4px
;
text-shadow
:
0
0
3px
rgba
(
0
,
0
,
0
,
0.5
);
}
.layer-status
{
font-size
:
12px
;
opacity
:
0.9
;
text-shadow
:
0
0
3px
rgba
(
0
,
0
,
0
,
0.5
);
}
/* 老化时间样式 */
...
...
@@ -424,10 +507,6 @@ export default {
.layer
{
position
:
absolute
;
left
:
0
;
border
:
1px
solid
rgba
(
100
,
180
,
255
,
0.6
);
box-shadow
:
0
4px
12px
rgba
(
0
,
0
,
0
,
0.6
),
inset
0
0
8px
rgba
(
100
,
200
,
255
,
0.3
);
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
...
...
@@ -438,22 +517,9 @@ export default {
}
.layer
:hover
{
background
:
linear-gradient
(
to
bottom
,
rgba
(
100
,
180
,
255
,
0.2
),
rgba
(
0
,
0
,
0
,
0.3
));
box-shadow
:
0
4px
15px
rgba
(
100
,
200
,
255
,
0.4
),
inset
0
0
10px
rgba
(
100
,
220
,
255
,
0.4
);
transform
:
translateY
(
-2px
);
}
.layer-depth
{
border-width
:
1px
3px
3px
1px
;
border-color
:
rgba
(
100
,
180
,
255
,
0.4
)
rgba
(
100
,
180
,
255
,
0.8
)
rgba
(
100
,
180
,
255
,
0.8
)
rgba
(
100
,
180
,
255
,
0.4
);
}
.right-content
{
flex
:
1
;
margin-left
:
80px
;
...
...
@@ -553,18 +619,19 @@ export default {
color
:
#fff
;
}
/* 右侧状态文本样式 */
.status-idle
{
color
:
#f
fcc0
0
;
color
:
#f
0f0f
0
;
font-weight
:
bold
;
}
.status-running
{
color
:
#6
4ffa
a
;
color
:
#6
7c23
a
;
font-weight
:
bold
;
}
.status-fault
{
color
:
#f
f3d3d
;
color
:
#f
56c6c
;
font-weight
:
bold
;
}
...
...
@@ -656,5 +723,4 @@ export default {
color
:
#66b1ff
;
transform
:
translateX
(
-5px
);
}
</
style
>
zhmes-agecal-web/src/views/screen/components/RoboticArm.vue
View file @
e9aecf8a
...
...
@@ -152,7 +152,7 @@ export default {
name
:
'RoboticArm'
,
data
()
{
return
{
status
:
'
unknown
'
,
// idle, running, error
status
:
'
idle
'
,
// idle, running, error
showAddDialog
:
false
,
trayCode
:
''
,
loadingCommands
:
[
...
...
@@ -235,7 +235,7 @@ export default {
this
.
websocket
.
onopen
=
()
=>
{
console
.
log
(
'机械臂指令WebSocket连接成功'
);
this
.
status
=
'
unknown
'
;
this
.
status
=
'
idle
'
;
this
.
sendWebSocketMessage
({
type
:
'request'
,
commands
:
[
'loading'
,
'unloading'
]
});
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment