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
cf69dc85
Commit
cf69dc85
authored
Aug 04, 2026
by
wanghao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1 老化过程中 获取卡号,获取IOT状态调整中
parent
2a1ab005
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
577 additions
and
168 deletions
+577
-168
PalletDeviceBindingController.java
...b/controller/equipment/PalletDeviceBindingController.java
+11
-0
Modbus4jUtils.java
...ain/java/com/zehong/system/modbus/util/Modbus4jUtils.java
+2
-1
CalibrationResultEventHandler.java
...ong/system/netty/event/CalibrationResultEventHandler.java
+2
-1
IPalletDeviceBindingService.java
...om/zehong/system/service/IPalletDeviceBindingService.java
+2
-0
PalletDeviceBindingServiceImpl.java
...g/system/service/impl/PalletDeviceBindingServiceImpl.java
+106
-2
RobotArmCommandServiceImpl.java
...ehong/system/service/impl/RobotArmCommandServiceImpl.java
+2
-1
AgingStageOneProcessJob.java
.../java/com/zehong/system/task/AgingStageOneProcessJob.java
+9
-0
AgingStageThreeProcessJob.java
...ava/com/zehong/system/task/AgingStageThreeProcessJob.java
+8
-0
AgingStageTwoProcessJob.java
.../java/com/zehong/system/task/AgingStageTwoProcessJob.java
+7
-0
AllCommandHandler.java
...c/main/java/com/zehong/system/task/AllCommandHandler.java
+6
-163
IotDataAndTokenUtil.java
...java/com/zehong/system/task/util/IotDataAndTokenUtil.java
+186
-0
binding.js
zhmes-agecal-web/src/api/palletDeviceBinding/binding.js
+7
-0
TrayBinding.vue
zhmes-agecal-web/src/views/screen/components/TrayBinding.vue
+1
-0
index.vue
zhmes-agecal-web/src/views/tool/iotStatus/index.vue
+228
-0
No files found.
zhmes-agecal-admin/src/main/java/com/zehong/web/controller/equipment/PalletDeviceBindingController.java
View file @
cf69dc85
...
...
@@ -124,6 +124,17 @@ public class PalletDeviceBindingController extends BaseController
return
toAjax
(
palletDeviceBindingService
.
batchUpdateDeviceCodeAndUnbindingTime
(
palletDeviceBindings
));
}
/**
* 实时获取iot状态
* @param trayCode f
* @return r
*/
@GetMapping
(
"/realTimeObtainIotStatusByTrayCode/{trayCode}"
)
public
AjaxResult
realTimeObtainIotStatusByTrayCode
(
@PathVariable
(
"trayCode"
)
String
trayCode
){
return
palletDeviceBindingService
.
realTimeObtainIotStatusByTrayCode
(
trayCode
);
}
/**
* 修改托盘绑定的设备列
*/
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/modbus/util/Modbus4jUtils.java
View file @
cf69dc85
...
...
@@ -36,6 +36,7 @@ public class Modbus4jUtils {
private
static
final
int
START_ADDRESS
=
0
;
// 对应40001
private
static
final
int
REGISTER_COUNT
=
16
;
// 读取15个寄存器
private
static
final
int
REGISTER_COUNT_36
=
36
;
// 读取36个寄存器
private
static
final
int
TARGET_VALUE
=
1
;
// 目标值(第二个寄存器的期望值)
private
static
final
int
MAX_RETRIES
=
3
;
// 最大重试次数
private
static
final
int
RETRY_DELAY
=
500
;
// 重试延迟(ms)// 监控参数
...
...
@@ -1103,7 +1104,7 @@ public class Modbus4jUtils {
throws
ModbusTransportException
{
// 创建读取请求
ReadHoldingRegistersRequest
request
=
Modbus4jUtils
.
getReadHoldingRegistersRequest
(
deviceId
,
START_ADDRESS
,
REGISTER_COUNT
);
ReadHoldingRegistersRequest
request
=
Modbus4jUtils
.
getReadHoldingRegistersRequest
(
deviceId
,
START_ADDRESS
,
REGISTER_COUNT
_36
);
// 发送请求并获取响应
ModbusResponse
response
=
master
.
send
(
request
);
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/netty/event/CalibrationResultEventHandler.java
View file @
cf69dc85
...
...
@@ -148,7 +148,8 @@ public class CalibrationResultEventHandler {
&&
palletDeviceBinding
.
getWriteSelfCheckStatus
()
!=
null
&&
palletDeviceBinding
.
getWriteSelfCheckStatus
()
==
1
&&
palletDeviceBinding
.
getModuleStatus
()
!=
null
&&
palletDeviceBinding
.
getModuleStatus
()
==
1
&&
palletDeviceBinding
.
getSimCardStatus
()
!=
null
&&
palletDeviceBinding
.
getSimCardStatus
()
==
1
&&
palletDeviceBinding
.
getNetworkStatus
()
!=
null
&&
palletDeviceBinding
.
getNetworkStatus
()
==
1
)
{
&&
palletDeviceBinding
.
getNetworkStatus
()
!=
null
&&
palletDeviceBinding
.
getNetworkStatus
()
==
1
&&
palletDeviceBinding
.
getIotStatus
()
!=
null
&&
palletDeviceBinding
.
getIotStatus
()
==
1
)
{
palletDeviceBinding
.
setStandardInspectResult
(
"1"
);
}
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/service/IPalletDeviceBindingService.java
View file @
cf69dc85
...
...
@@ -59,6 +59,8 @@ public interface IPalletDeviceBindingService
public
int
batchUpdateDeviceCodeAndUnbindingTime
(
List
<
PalletDeviceBinding
>
palletDeviceBindingList
);
public
AjaxResult
realTimeObtainIotStatusByTrayCode
(
String
trayCode
);
/**
* 修改托盘绑定的设备列
*
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/service/impl/PalletDeviceBindingServiceImpl.java
View file @
cf69dc85
...
...
@@ -3,6 +3,8 @@ package com.zehong.system.service.impl;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
com.google.common.util.concurrent.RateLimiter
;
import
com.zehong.common.constant.Constants
;
import
com.zehong.common.constant.RoboticArmConstans
;
import
com.zehong.common.core.domain.AjaxResult
;
import
com.zehong.common.utils.DateUtils
;
...
...
@@ -13,14 +15,14 @@ import com.zehong.system.mapper.*;
import
com.zehong.system.service.*
;
import
com.zehong.system.task.DeviceTaskScheduler
;
import
com.zehong.system.task.event.ReceivedNbCodeEvent
;
import
com.zehong.system.task.util.IotDataAndTokenUtil
;
import
org.quartz.SchedulerException
;
import
org.springframework.context.ApplicationEventPublisher
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
javax.annotation.Resource
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.*
;
import
java.util.stream.Collectors
;
/**
...
...
@@ -63,6 +65,11 @@ public class PalletDeviceBindingServiceImpl implements IPalletDeviceBindingServi
@Resource
private
ApplicationEventPublisher
eventPublisher
;
// 新增事件发布器
@Resource
private
IotDataAndTokenUtil
iotDataAndTokenUtil
;
// 根据 IOT 接口文档的 QPS 限制调整,如果接口说限制 50 QPS,就设 45 留余量
private
static
final
RateLimiter
RATE_LIMITER
=
RateLimiter
.
create
(
2
);
/**
* 查询托盘绑定的设备列
*
...
...
@@ -264,6 +271,103 @@ public class PalletDeviceBindingServiceImpl implements IPalletDeviceBindingServi
return
palletDeviceBindingMapper
.
batchUpdateDeviceCodeAndUnbindingTime
(
palletDeviceBindingList
);
}
/**
* 实时获取物联网状态
*
* @param trayCode 托盘编号
* @return 结果
*/
@Override
public
AjaxResult
realTimeObtainIotStatusByTrayCode
(
String
trayCode
)
{
if
(
StringUtils
.
isBlank
(
trayCode
)){
return
AjaxResult
.
error
(
"托盘编号不能为空"
);
}
PalletDeviceBinding
palletDeviceBinding
=
new
PalletDeviceBinding
();
palletDeviceBinding
.
setfTrayCode
(
trayCode
);
List
<
PalletDeviceBinding
>
palletDeviceBindings
=
palletDeviceBindingMapper
.
selectPalletDeviceBindingList
(
palletDeviceBinding
);
if
(
palletDeviceBindings
==
null
||
palletDeviceBindings
.
size
()
==
0
){
return
AjaxResult
.
error
(
"无此托盘"
);
}
// 2. 按主板码分组,并过滤掉无效数据(同时提前处理无需调接口的)
// // 只留 nbCode 有效的 // 网络状态为 1
Map
<
String
,
List
<
PalletDeviceBinding
>>
groupByMotherboard
=
palletDeviceBindings
.
stream
()
.
filter
(
b
->
org
.
apache
.
commons
.
lang3
.
StringUtils
.
isNotBlank
(
b
.
getNbCode
())
&&
b
.
getNetworkStatus
()
!=
null
&&
b
.
getNetworkStatus
()
==
1
)
.
collect
(
Collectors
.
groupingBy
(
PalletDeviceBinding:
:
getMotherboardCode
));
// 处理 nbCode 为空的(直接设状态为 2,加入待更新列表)
for
(
PalletDeviceBinding
binding
:
palletDeviceBindings
)
{
if
(
org
.
apache
.
commons
.
lang3
.
StringUtils
.
isBlank
(
binding
.
getNbCode
()))
{
binding
.
setIotStatus
(
2
);
}
// 顺便处理网络状态异常(但不要覆盖后续 IOT 查询结果,网络异常只是前置标记)
// 注意:如果网络状态 !=1,但 IOT 查询成功,应该以 IOT 为准,这里先不 set,留给后面判断
}
// 3. 获取 IOT Token(只获取一次)
String
iotToken
=
iotDataAndTokenUtil
.
getIOTToken
();
if
(
org
.
apache
.
commons
.
lang3
.
StringUtils
.
isBlank
(
iotToken
))
{
throw
new
RuntimeException
(
"IOT token未获取"
);
}
// 4. 构造通用请求头
Map
<
String
,
String
>
headers
=
new
HashMap
<>();
headers
.
put
(
"Authorization"
,
iotToken
);
headers
.
put
(
"Content-Type"
,
"application/json"
);
String
iotApiUrl
=
sysConfigService
.
directSelectConfigByKey
(
Constants
.
IOT_DEVICES_SCAN
);
// 5. 循环处理每个主板码(带限流)
for
(
Map
.
Entry
<
String
,
List
<
PalletDeviceBinding
>>
entry
:
groupByMotherboard
.
entrySet
())
{
String
motherboardCode
=
entry
.
getKey
();
List
<
PalletDeviceBinding
>
sameBoardDevices
=
entry
.
getValue
();
// 取任意一个设备的 nbCode(因为同一主板下的 nbCode 理论上一致,但为了严谨取第一个非空的)
String
nbCode
=
sameBoardDevices
.
stream
()
.
map
(
PalletDeviceBinding:
:
getNbCode
)
.
filter
(
org
.
apache
.
commons
.
lang3
.
StringUtils
::
isNotBlank
)
.
findFirst
()
.
orElse
(
null
);
if
(
nbCode
==
null
)
{
continue
;
}
// ★★★ Guava 限流(阻塞等待令牌) ★★★
RATE_LIMITER
.
acquire
();
// 调用 IOT 接口
Map
<
String
,
Object
>
params
=
new
HashMap
<>();
params
.
put
(
"number"
,
nbCode
);
String
result
=
null
;
try
{
result
=
HttpUtils
.
get
(
iotApiUrl
,
headers
,
params
);
}
catch
(
Exception
e
)
{
log
.
error
(
"调用IOT接口异常, motherboardCode: {}, nbCode: {}"
,
motherboardCode
,
nbCode
,
e
);
}
// 6. 根据结果设置状态(应用到该主板下的所有设备)
Integer
statusToSet
;
if
(
org
.
apache
.
commons
.
lang3
.
StringUtils
.
isNotBlank
(
result
))
{
Map
<
String
,
String
>
dataMap
=
iotDataAndTokenUtil
.
processIotData
(
result
);
if
(
dataMap
!=
null
&&
!
dataMap
.
isEmpty
())
{
statusToSet
=
1
;
// IOT数据正常
}
else
{
statusToSet
=
0
;
// IOT数据为空
}
}
else
{
statusToSet
=
0
;
// 请求失败
}
// 将状态设置给该组所有设备,并加入待更新列表
for
(
PalletDeviceBinding
device
:
sameBoardDevices
)
{
device
.
setIotStatus
(
statusToSet
);
}
}
return
AjaxResult
.
success
(
palletDeviceBindings
);
}
/**
* 修改托盘绑定的设备列
*
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/service/impl/RobotArmCommandServiceImpl.java
View file @
cf69dc85
...
...
@@ -22,6 +22,7 @@ import com.zehong.system.netty.handler.NettyUdpServerHandler;
import
com.zehong.system.service.IConveyorBeltIpMaintainService
;
import
com.zehong.system.service.websocket.RobotArmWebSocketHandler
;
import
com.zehong.system.task.event.CheckPowerOnCommandEvent
;
import
com.zehong.system.task.event.IotStatusEvent
;
import
com.zehong.system.task.event.PowerOffCommandEvent
;
import
com.zehong.system.udp.UdpCommandSender
;
import
org.slf4j.Logger
;
...
...
@@ -190,7 +191,7 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
Modbus4jUtils
.
writeCoil
(
master
,
1
,
registerOffsetInt
,
false
);
log
.
info
(
"已发送断电指令 - 设备:{} 层:{}"
,
tEquipmentInfo
.
getfEquipmentCode
(),
layer
);
master
.
destroy
();
eventPublisher
.
publishEvent
(
new
IotStatusEvent
(
this
,
storeyCode
));
// 如果正常 则发送 IOT请求
}
catch
(
ModbusTransportException
|
ModbusInitException
e
)
{
log
.
info
(
"下料发送断电指令失败 - 设备:{} 层:{}"
,
tEquipmentInfo
.
getfEquipmentCode
(),
layer
);
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/task/AgingStageOneProcessJob.java
View file @
cf69dc85
...
...
@@ -182,6 +182,15 @@ public class AgingStageOneProcessJob implements Job {
int
i
=
Modbus4jUtils
.
writeSelfCheckStatus
(
master
,
deviceId
);
binding
.
setWriteSelfCheckStatus
(
i
);
}
// 设置卡号
StringBuilder
simCardNoBuilder
=
new
StringBuilder
();
for
(
int
i
=
17
;
i
<=
36
;
i
++)
{
simCardNoBuilder
.
append
(
result
[
i
]);
}
String
simCardNo
=
simCardNoBuilder
.
toString
();
binding
.
setSimCardNo
(
simCardNo
);
// 6. 更新数据库
palletDeviceBindingMapper
.
updatePalletDeviceBinding
(
binding
);
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/task/AgingStageThreeProcessJob.java
View file @
cf69dc85
...
...
@@ -222,6 +222,14 @@ public class AgingStageThreeProcessJob implements Job {
if
(
"5"
.
equals
(
binding
.
getDeviceStatus
()))
{
binding
.
setWriteTimeStatus
(
"0"
);
}
// 设置卡号
StringBuilder
simCardNoBuilder
=
new
StringBuilder
();
for
(
int
i
=
17
;
i
<=
36
;
i
++)
{
simCardNoBuilder
.
append
(
result
[
i
]);
}
String
simCardNo
=
simCardNoBuilder
.
toString
();
binding
.
setSimCardNo
(
simCardNo
);
// 5. 更新数据库
palletDeviceBindingMapper
.
updatePalletDeviceBinding
(
binding
);
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/task/AgingStageTwoProcessJob.java
View file @
cf69dc85
...
...
@@ -250,6 +250,13 @@ public class AgingStageTwoProcessJob implements Job {
binding
.
setWriteSelfCheckStatus
(
i
);
}
// 设置卡号
StringBuilder
simCardNoBuilder
=
new
StringBuilder
();
for
(
int
i
=
17
;
i
<=
36
;
i
++)
{
simCardNoBuilder
.
append
(
result
[
i
]);
}
String
simCardNo
=
simCardNoBuilder
.
toString
();
binding
.
setSimCardNo
(
simCardNo
);
// 5. 更新数据库
palletDeviceBindingMapper
.
updatePalletDeviceBinding
(
binding
);
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/task/AllCommandHandler.java
View file @
cf69dc85
...
...
@@ -9,8 +9,6 @@ import com.serotonin.modbus4j.exception.ModbusInitException;
import
com.serotonin.modbus4j.exception.ModbusTransportException
;
import
com.zehong.common.constant.Constants
;
import
com.zehong.common.constant.RoboticArmConstans
;
import
com.zehong.common.core.domain.AjaxResult
;
import
com.zehong.common.core.redis.RedisCache
;
import
com.zehong.common.utils.DateUtils
;
import
com.zehong.common.utils.http.HttpUtils
;
import
com.zehong.system.domain.*
;
...
...
@@ -25,6 +23,7 @@ import com.zehong.system.task.event.CheckPowerOnCommandEvent;
import
com.zehong.system.task.event.IotStatusEvent
;
import
com.zehong.system.task.event.PowerOffCommandEvent
;
import
com.zehong.system.task.event.ReceivedNbCodeEvent
;
import
com.zehong.system.task.util.IotDataAndTokenUtil
;
import
org.apache.commons.collections4.CollectionUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.context.event.EventListener
;
...
...
@@ -34,7 +33,6 @@ import org.springframework.transaction.annotation.Transactional;
import
javax.annotation.Resource
;
import
java.util.*
;
import
java.util.concurrent.TimeUnit
;
import
java.util.stream.Collectors
;
/**
...
...
@@ -76,8 +74,7 @@ public class AllCommandHandler {
private
IReceivedNbFailureHistoryService
receivedNbFailureHistoryService
;
@Resource
private
RedisCache
redisCache
;
private
IotDataAndTokenUtil
iotDataAndTokenUtil
;
@Resource
private
ISysConfigService
sysConfigService
;
...
...
@@ -239,8 +236,9 @@ public class AllCommandHandler {
}
// 2. 按主板码分组,并过滤掉无效数据(同时提前处理无需调接口的)
// // 只留 nbCode 有效的 // 网络状态为 1
Map
<
String
,
List
<
PalletDeviceBinding
>>
groupByMotherboard
=
bindings
.
stream
()
.
filter
(
b
->
StringUtils
.
isNotBlank
(
b
.
getNbCode
())
)
// 只留 nbCode 有效的
.
filter
(
b
->
StringUtils
.
isNotBlank
(
b
.
getNbCode
())
&&
b
.
getNetworkStatus
()
==
1
)
.
collect
(
Collectors
.
groupingBy
(
PalletDeviceBinding:
:
getMotherboardCode
));
// 处理 nbCode 为空的(直接设状态为 2,加入待更新列表)
...
...
@@ -263,7 +261,7 @@ public class AllCommandHandler {
}
// 3. 获取 IOT Token(只获取一次)
String
iotToken
=
getIOTToken
();
String
iotToken
=
iotDataAndTokenUtil
.
getIOTToken
();
if
(
StringUtils
.
isBlank
(
iotToken
))
{
throw
new
RuntimeException
(
"IOT token未获取"
);
}
...
...
@@ -305,7 +303,7 @@ public class AllCommandHandler {
// 6. 根据结果设置状态(应用到该主板下的所有设备)
Integer
statusToSet
;
if
(
StringUtils
.
isNotBlank
(
result
))
{
Map
<
String
,
String
>
dataMap
=
processIotData
(
result
);
Map
<
String
,
String
>
dataMap
=
iotDataAndTokenUtil
.
processIotData
(
result
);
if
(
dataMap
!=
null
&&
!
dataMap
.
isEmpty
())
{
statusToSet
=
1
;
// IOT数据正常
}
else
{
...
...
@@ -328,161 +326,6 @@ public class AllCommandHandler {
}
}
/**
* 处理MES返回的数据
*/
private
Map
<
String
,
String
>
processIotData
(
String
data
)
{
Map
<
String
,
String
>
deviceStatus
=
new
HashMap
<>();
// 根据实际业务需求处理数据
// 这里只是示例,具体实现根据您的业务逻辑
try
{
JSONObject
jsonObject
=
JSON
.
parseObject
(
data
);
Object
data1
=
jsonObject
.
get
(
"data"
);
if
(
data1
==
null
)
{
return
deviceStatus
;
}
JSONObject
jsonData
=
JSON
.
parseObject
(
data1
.
toString
());
deviceStatus
.
put
(
"number"
,
jsonData
.
getString
(
"number"
)
==
null
?
""
:
jsonData
.
getString
(
"number"
));
deviceStatus
.
put
(
"title"
,
jsonData
.
getString
(
"title"
)
==
null
?
""
:
jsonData
.
getString
(
"title"
));
deviceStatus
.
put
(
"deviceType"
,
jsonData
.
getString
(
"devices_type"
)
==
null
?
""
:
jsonData
.
getString
(
"devices_type"
));
deviceStatus
.
put
(
"modelTitle"
,
jsonData
.
getString
(
"model_title"
)
==
null
?
""
:
jsonData
.
getString
(
"model_title"
));
deviceStatus
.
put
(
"batchNum"
,
jsonData
.
getString
(
"batchNum"
)
==
null
?
""
:
jsonData
.
getString
(
"batchNum"
));
deviceStatus
.
put
(
"gas"
,
jsonData
.
getString
(
"gas"
)
==
null
?
""
:
jsonData
.
getString
(
"gas"
));
deviceStatus
.
put
(
"unit"
,
jsonData
.
getString
(
"unit"
)
==
null
?
""
:
jsonData
.
getString
(
"unit"
));
deviceStatus
.
put
(
"status"
,
jsonData
.
getString
(
"report_status"
)
==
null
?
""
:
jsonData
.
getString
(
"report_status"
));
deviceStatus
.
put
(
"concentration"
,
jsonData
.
getString
(
"report_nd"
)
==
null
?
""
:
jsonData
.
getString
(
"report_nd"
));
deviceStatus
.
put
(
"reportTime"
,
jsonData
.
getString
(
"report_time"
)
==
null
?
""
:
jsonData
.
getString
(
"report_time"
));
// 处理数据逻辑...
return
deviceStatus
;
}
catch
(
Exception
e
)
{
return
new
HashMap
<>();
}
}
/**
* 获取MES token
*/
private
String
getIOTToken
()
{
// 1. 先从Redis中获取token
Object
tokenObj
=
redisCache
.
getCacheObject
(
Constants
.
IOT_LOGIN_TOKEN
);
if
(
tokenObj
!=
null
)
{
String
token
=
tokenObj
.
toString
();
// 检查token是否即将过期(提前5分钟刷新)
long
expireTime
=
redisCache
.
getExpire
(
Constants
.
IOT_LOGIN_TOKEN
,
TimeUnit
.
MINUTES
);
if
(
expireTime
>
10
)
{
// 大于10分钟,直接返回
return
token
;
}
}
// 2. 如果Redis中没有或即将过期,重新获取token
return
refreshIOTToken
();
}
/**
* 刷新MES token
*/
private
String
refreshIOTToken
()
{
try
{
// 1. 获取登录配置信息
String
loginUrl
=
sysConfigService
.
directSelectConfigByKey
(
Constants
.
IOT_LOGIN_ADDRESS
);
String
username
=
sysConfigService
.
directSelectConfigByKey
(
Constants
.
IOT_LOGIN_USERNAME
);
String
password
=
sysConfigService
.
directSelectConfigByKey
(
Constants
.
IOT_LOGIN_PASSWORD
);
if
(
org
.
apache
.
commons
.
lang3
.
StringUtils
.
isAnyBlank
(
loginUrl
,
username
,
password
))
{
throw
new
RuntimeException
(
"MES登录配置信息不完整"
);
}
// 2. 构造登录参数
Map
<
String
,
String
>
loginParams
=
new
HashMap
<>();
loginParams
.
put
(
"username"
,
username
);
loginParams
.
put
(
"password"
,
password
);
// 3. 添加请求头
Map
<
String
,
String
>
headers
=
new
HashMap
<>();
// 3. 调用登录接口
String
response
=
HttpUtils
.
postJson
(
loginUrl
,
headers
,
loginParams
);
// 5. 解析响应
if
(
org
.
apache
.
commons
.
lang3
.
StringUtils
.
isNotBlank
(
response
))
{
// 尝试解析为JSON
try
{
Map
<
String
,
Object
>
responseMap
=
JSON
.
parseObject
(
response
,
Map
.
class
);
// 检查是否有错误
if
(
responseMap
.
containsKey
(
"code"
)
&&
!
"200"
.
equals
(
String
.
valueOf
(
responseMap
.
get
(
"code"
))))
{
String
errorMsg
=
responseMap
.
containsKey
(
"msg"
)
?
String
.
valueOf
(
responseMap
.
get
(
"msg"
))
:
"登录失败"
;
System
.
err
.
println
(
"登录失败: "
+
errorMsg
);
return
null
;
}
// 根据实际响应结构提取token
String
token
=
extractTokenFromResponse
(
responseMap
);
if
(
org
.
apache
.
commons
.
lang3
.
StringUtils
.
isNotBlank
(
token
))
{
// 存储token到Redis
redisCache
.
setCacheObject
(
Constants
.
IOT_LOGIN_TOKEN
,
token
,
1
,
TimeUnit
.
HOURS
);
System
.
out
.
println
(
"登录成功,token: "
+
token
);
return
token
;
}
}
catch
(
Exception
e
)
{
System
.
err
.
println
(
"解析响应失败: "
+
e
.
getMessage
());
e
.
printStackTrace
();
}
}
return
null
;
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"获取MES token失败"
);
}
}
/**
* 从响应中提取token(根据实际响应格式调整)
*/
private
String
extractTokenFromResponse
(
Map
<
String
,
Object
>
responseMap
)
{
// 根据实际响应结构提取token
// 例如:responseMap.get("data").get("token")
// 示例1:如果token在顶层
if
(
responseMap
.
containsKey
(
"token"
))
{
return
String
.
valueOf
(
responseMap
.
get
(
"token"
));
}
// 示例2:如果token在data对象中
if
(
responseMap
.
containsKey
(
"data"
))
{
Object
data
=
responseMap
.
get
(
"data"
);
if
(
data
instanceof
Map
)
{
Map
<?,
?>
dataMap
=
(
Map
<?,
?>)
data
;
if
(
dataMap
.
containsKey
(
"access_token"
))
{
return
String
.
valueOf
(
dataMap
.
get
(
"access_token"
));
}
}
}
// 示例3:如果token在其他字段中
String
[]
possibleTokenKeys
=
{
"access_token"
,
"accessToken"
,
"Authorization"
,
"authToken"
};
for
(
String
key
:
possibleTokenKeys
)
{
if
(
responseMap
.
containsKey
(
key
))
{
return
String
.
valueOf
(
responseMap
.
get
(
key
));
}
}
// 如果都找不到,打印整个响应用于调试
System
.
out
.
println
(
"无法找到token,完整响应: "
+
JSON
.
toJSONString
(
responseMap
));
return
null
;
}
/**
* 接收到NB码
* @param event event
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/task/util/IotDataAndTokenUtil.java
0 → 100644
View file @
cf69dc85
package
com
.
zehong
.
system
.
task
.
util
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
com.zehong.common.constant.Constants
;
import
com.zehong.common.core.redis.RedisCache
;
import
com.zehong.common.utils.http.HttpUtils
;
import
com.zehong.system.service.ISysConfigService
;
import
org.springframework.stereotype.Component
;
import
javax.annotation.Resource
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.concurrent.TimeUnit
;
/**
* @author lenovo
* @date 2026/8/4
* @description tokenUtil
*/
@Component
public
class
IotDataAndTokenUtil
{
@Resource
private
RedisCache
redisCache
;
@Resource
private
ISysConfigService
sysConfigService
;
/**
* 获取MES token
*/
public
String
getIOTToken
()
{
// 1. 先从Redis中获取token
Object
tokenObj
=
redisCache
.
getCacheObject
(
Constants
.
IOT_LOGIN_TOKEN
);
if
(
tokenObj
!=
null
)
{
String
token
=
tokenObj
.
toString
();
// 检查token是否即将过期(提前5分钟刷新)
long
expireTime
=
redisCache
.
getExpire
(
Constants
.
IOT_LOGIN_TOKEN
,
TimeUnit
.
MINUTES
);
if
(
expireTime
>
10
)
{
// 大于10分钟,直接返回
return
token
;
}
}
// 2. 如果Redis中没有或即将过期,重新获取token
return
refreshIOTToken
();
}
/**
* 刷新MES token
*/
private
String
refreshIOTToken
()
{
try
{
// 1. 获取登录配置信息
String
loginUrl
=
sysConfigService
.
directSelectConfigByKey
(
Constants
.
IOT_LOGIN_ADDRESS
);
String
username
=
sysConfigService
.
directSelectConfigByKey
(
Constants
.
IOT_LOGIN_USERNAME
);
String
password
=
sysConfigService
.
directSelectConfigByKey
(
Constants
.
IOT_LOGIN_PASSWORD
);
if
(
org
.
apache
.
commons
.
lang3
.
StringUtils
.
isAnyBlank
(
loginUrl
,
username
,
password
))
{
throw
new
RuntimeException
(
"MES登录配置信息不完整"
);
}
// 2. 构造登录参数
Map
<
String
,
String
>
loginParams
=
new
HashMap
<>();
loginParams
.
put
(
"username"
,
username
);
loginParams
.
put
(
"password"
,
password
);
// 3. 添加请求头
Map
<
String
,
String
>
headers
=
new
HashMap
<>();
// 3. 调用登录接口
String
response
=
HttpUtils
.
postJson
(
loginUrl
,
headers
,
loginParams
);
// 5. 解析响应
if
(
org
.
apache
.
commons
.
lang3
.
StringUtils
.
isNotBlank
(
response
))
{
// 尝试解析为JSON
try
{
Map
<
String
,
Object
>
responseMap
=
JSON
.
parseObject
(
response
,
Map
.
class
);
// 检查是否有错误
if
(
responseMap
.
containsKey
(
"code"
)
&&
!
"200"
.
equals
(
String
.
valueOf
(
responseMap
.
get
(
"code"
))))
{
String
errorMsg
=
responseMap
.
containsKey
(
"msg"
)
?
String
.
valueOf
(
responseMap
.
get
(
"msg"
))
:
"登录失败"
;
System
.
err
.
println
(
"登录失败: "
+
errorMsg
);
return
null
;
}
// 根据实际响应结构提取token
String
token
=
extractTokenFromResponse
(
responseMap
);
if
(
org
.
apache
.
commons
.
lang3
.
StringUtils
.
isNotBlank
(
token
))
{
// 存储token到Redis
redisCache
.
setCacheObject
(
Constants
.
IOT_LOGIN_TOKEN
,
token
,
1
,
TimeUnit
.
HOURS
);
System
.
out
.
println
(
"登录成功,token: "
+
token
);
return
token
;
}
}
catch
(
Exception
e
)
{
System
.
err
.
println
(
"解析响应失败: "
+
e
.
getMessage
());
e
.
printStackTrace
();
}
}
return
null
;
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"获取MES token失败"
);
}
}
/**
* 从响应中提取token(根据实际响应格式调整)
*/
private
String
extractTokenFromResponse
(
Map
<
String
,
Object
>
responseMap
)
{
// 根据实际响应结构提取token
// 例如:responseMap.get("data").get("token")
// 示例1:如果token在顶层
if
(
responseMap
.
containsKey
(
"token"
))
{
return
String
.
valueOf
(
responseMap
.
get
(
"token"
));
}
// 示例2:如果token在data对象中
if
(
responseMap
.
containsKey
(
"data"
))
{
Object
data
=
responseMap
.
get
(
"data"
);
if
(
data
instanceof
Map
)
{
Map
<?,
?>
dataMap
=
(
Map
<?,
?>)
data
;
if
(
dataMap
.
containsKey
(
"access_token"
))
{
return
String
.
valueOf
(
dataMap
.
get
(
"access_token"
));
}
}
}
// 示例3:如果token在其他字段中
String
[]
possibleTokenKeys
=
{
"access_token"
,
"accessToken"
,
"Authorization"
,
"authToken"
};
for
(
String
key
:
possibleTokenKeys
)
{
if
(
responseMap
.
containsKey
(
key
))
{
return
String
.
valueOf
(
responseMap
.
get
(
key
));
}
}
// 如果都找不到,打印整个响应用于调试
System
.
out
.
println
(
"无法找到token,完整响应: "
+
JSON
.
toJSONString
(
responseMap
));
return
null
;
}
/**
* 处理MES返回的数据
*/
public
Map
<
String
,
String
>
processIotData
(
String
data
)
{
Map
<
String
,
String
>
deviceStatus
=
new
HashMap
<>();
// 根据实际业务需求处理数据
// 这里只是示例,具体实现根据您的业务逻辑
try
{
JSONObject
jsonObject
=
JSON
.
parseObject
(
data
);
Object
data1
=
jsonObject
.
get
(
"data"
);
if
(
data1
==
null
)
{
return
deviceStatus
;
}
JSONObject
jsonData
=
JSON
.
parseObject
(
data1
.
toString
());
deviceStatus
.
put
(
"number"
,
jsonData
.
getString
(
"number"
)
==
null
?
""
:
jsonData
.
getString
(
"number"
));
deviceStatus
.
put
(
"title"
,
jsonData
.
getString
(
"title"
)
==
null
?
""
:
jsonData
.
getString
(
"title"
));
deviceStatus
.
put
(
"deviceType"
,
jsonData
.
getString
(
"devices_type"
)
==
null
?
""
:
jsonData
.
getString
(
"devices_type"
));
deviceStatus
.
put
(
"modelTitle"
,
jsonData
.
getString
(
"model_title"
)
==
null
?
""
:
jsonData
.
getString
(
"model_title"
));
deviceStatus
.
put
(
"batchNum"
,
jsonData
.
getString
(
"batchNum"
)
==
null
?
""
:
jsonData
.
getString
(
"batchNum"
));
deviceStatus
.
put
(
"gas"
,
jsonData
.
getString
(
"gas"
)
==
null
?
""
:
jsonData
.
getString
(
"gas"
));
deviceStatus
.
put
(
"unit"
,
jsonData
.
getString
(
"unit"
)
==
null
?
""
:
jsonData
.
getString
(
"unit"
));
deviceStatus
.
put
(
"status"
,
jsonData
.
getString
(
"report_status"
)
==
null
?
""
:
jsonData
.
getString
(
"report_status"
));
deviceStatus
.
put
(
"concentration"
,
jsonData
.
getString
(
"report_nd"
)
==
null
?
""
:
jsonData
.
getString
(
"report_nd"
));
deviceStatus
.
put
(
"reportTime"
,
jsonData
.
getString
(
"report_time"
)
==
null
?
""
:
jsonData
.
getString
(
"report_time"
));
// 处理数据逻辑...
return
deviceStatus
;
}
catch
(
Exception
e
)
{
return
new
HashMap
<>();
}
}
}
zhmes-agecal-web/src/api/palletDeviceBinding/binding.js
View file @
cf69dc85
...
...
@@ -73,6 +73,13 @@ export function unbindAllDeviceNoUploadMes(trayId){
})
}
export
function
realTimeObtainIotStatusByTrayCode
(
trayCode
){
return
request
({
url
:
'/palletDevice/binding/realTimeObtainIotStatusByTrayCode/'
+
trayCode
,
method
:
'get'
})
}
// 修改托盘绑定的设备列
export
function
updateBinding
(
data
)
{
return
request
({
...
...
zhmes-agecal-web/src/views/screen/components/TrayBinding.vue
View file @
cf69dc85
...
...
@@ -367,6 +367,7 @@ export default {
(
device
.
runTimeStatus
!=
null
&&
device
.
runTimeStatus
===
'0'
)
||
(
device
.
relayStatus
!=
null
&&
device
.
relayStatus
===
0
)
||
(
device
.
pulseStatus
!=
null
&&
device
.
pulseStatus
===
0
)
||
(
device
.
iotStatus
!=
null
&&
device
.
iotStatus
===
0
)
||
device
.
moduleStatus
===
0
||
device
.
simCardStatus
===
0
||
device
.
networkStatus
===
0
;
},
...
...
zhmes-agecal-web/src/views/tool/iotStatus/index.vue
0 → 100644
View file @
cf69dc85
<
template
>
<div
class=
"iot-status-container"
>
<!-- 搜索区域 -->
<el-form
:inline=
"true"
class=
"search-form"
>
<el-form-item>
<el-input
v-model=
"trayCode"
placeholder=
"请输入托盘号"
clearable
size=
"medium"
@
keyup
.
enter
.
native=
"handleSearch"
/>
</el-form-item>
<el-form-item>
<el-button
type=
"primary"
icon=
"el-icon-search"
@
click=
"handleSearch"
>
查询
</el-button>
</el-form-item>
</el-form>
<!-- 加载状态 -->
<div
v-loading=
"loading"
class=
"result-area"
>
<!-- 无数据提示 -->
<el-empty
v-if=
"!loading && matrixData.length === 0"
description=
"暂无数据,请搜索托盘号"
/>
<!-- 矩阵网格 8行 x 9列 -->
<div
v-else
class=
"matrix-grid"
>
<div
v-for=
"(row, rowIndex) in matrixData"
:key=
"'row-' + rowIndex"
class=
"matrix-row"
>
<div
v-for=
"(cell, colIndex) in row"
:key=
"'col-' + colIndex"
class=
"matrix-cell"
>
<!-- 有设备数据显示圆点 -->
<el-tooltip
v-if=
"cell"
placement=
"top"
:content=
"tooltipContent(cell)"
effect=
"dark"
>
<div
class=
"dot"
:class=
"
{
'dot-green': isNormal(cell),
'dot-red': !isNormal(cell)
}"
>
</div>
</el-tooltip>
<!-- 无设备数据展示空位(灰色小圆) -->
<div
v-else
class=
"dot dot-empty"
></div>
</div>
</div>
</div>
</div>
</div>
</
template
>
<
script
>
import
{
realTimeObtainIotStatusByTrayCode
}
from
'@/api/palletDeviceBinding/binding'
export
default
{
name
:
'SearchIotStatus'
,
data
()
{
return
{
trayCode
:
''
,
loading
:
false
,
deviceList
:
[],
// 接口返回的原始数组
matrixData
:
[]
// 8行 x 9列的二维数组
}
},
methods
:
{
/** 搜索 */
handleSearch
()
{
if
(
!
this
.
trayCode
.
trim
())
{
this
.
$message
.
warning
(
'请输入托盘号'
)
return
}
this
.
loading
=
true
realTimeObtainIotStatusByTrayCode
(
this
.
trayCode
.
trim
())
.
then
(
res
=>
{
this
.
deviceList
=
res
.
data
||
[]
if
(
this
.
deviceList
.
length
===
0
)
{
this
.
$message
.
info
(
'未查询到设备信息'
)
}
this
.
buildMatrix
()
})
.
catch
(
err
=>
{
this
.
$message
.
error
(
'查询失败:'
+
(
err
.
message
||
'未知错误'
))
this
.
deviceList
=
[]
this
.
matrixData
=
[]
})
.
finally
(()
=>
{
this
.
loading
=
false
})
},
/** 根据 deviceList 构建 8行 x 9列 的矩阵 */
buildMatrix
()
{
// 初始化 8行 x 9列,全部为 null
const
rows
=
8
const
cols
=
9
const
matrix
=
Array
.
from
({
length
:
rows
},
()
=>
Array
(
cols
).
fill
(
null
))
// 填充数据:row 和 col 从 1 开始,映射到索引 0 开始
this
.
deviceList
.
forEach
(
item
=>
{
const
rowIdx
=
(
item
.
row
||
0
)
-
1
const
colIdx
=
(
item
.
col
||
0
)
-
1
// 仅当行列在有效范围内才填充
if
(
rowIdx
>=
0
&&
rowIdx
<
rows
&&
colIdx
>=
0
&&
colIdx
<
cols
)
{
matrix
[
rowIdx
][
colIdx
]
=
item
}
})
this
.
matrixData
=
matrix
},
/** 判断该设备是否正常(网络和IOT均为正常) */
isNormal
(
cell
)
{
if
(
!
cell
)
return
false
const
networkOk
=
cell
.
networkStatus
===
1
const
iotOk
=
cell
.
iotStatus
===
1
return
networkOk
&&
iotOk
},
/** 生成悬停提示内容 */
tooltipContent
(
cell
)
{
if
(
!
cell
)
return
''
const
rows
=
[
`行:
${
cell
.
row
??
'-'
}
`,
`
列:
$
{
cell
.
col
??
'-'
}
`,
`
设备编号:
$
{
cell
.
motherboardCode
||
'-'
}
`,
`
NB
码:
$
{
cell
.
nbCode
||
'-'
}
`,
`
网络状态:
$
{
this
.
formatNetworkStatus
(
cell
.
networkStatus
)}
`,
`
IOT
状态:
$
{
this
.
formatIotStatus
(
cell
.
iotStatus
)}
`
]
return rows.join('\n')
},
/** 格式化网络状态显示文本(用于tooltip) */
formatNetworkStatus(status) {
if (status === null || status === undefined) return '空'
return status === 1 ? '正常' : '异常'
},
/** 格式化IOT状态显示文本(用于tooltip) */
formatIotStatus(status) {
if (status === null || status === undefined) return '空'
const map = {
0: '异常',
1: '正常',
2: 'Nb码为空',
3: '网络状态异常'
}
return map[status] || '未知'
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.iot-status-container
{
padding
:
20px
;
.search-form
{
margin-bottom
:
20px
;
text-align
:
center
;
}
.result-area
{
min-height
:
200px
;
}
.matrix-grid
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
gap
:
8px
;
margin-top
:
10px
;
}
.matrix-row
{
display
:
flex
;
gap
:
8px
;
}
.matrix-cell
{
width
:
40px
;
height
:
40px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
.dot
{
width
:
28px
;
height
:
28px
;
border-radius
:
50%
;
border
:
2px
solid
#dcdfe6
;
background-color
:
#f5f7fa
;
transition
:
all
0
.2s
;
cursor
:
default
;
&
.dot-green
{
background-color
:
#67c23a
;
border-color
:
#67c23a
;
box-shadow
:
0
2px
6px
rgba
(
103
,
194
,
58
,
0
.3
);
}
&
.dot-red
{
background-color
:
#f56c6c
;
border-color
:
#f56c6c
;
box-shadow
:
0
2px
6px
rgba
(
245
,
108
,
108
,
0
.3
);
}
&
.dot-empty
{
background-color
:
#e4e7ed
;
border-color
:
#c0c4cc
;
opacity
:
0
.4
;
}
&
:hover
{
transform
:
scale
(
1
.1
);
}
}
}
</
style
>
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