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
f8da175f
Commit
f8da175f
authored
Jun 17, 2025
by
wanghao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1 托盘和 设备 数据绑定界面开发中
parent
2b92be96
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1081 additions
and
150 deletions
+1081
-150
TStoreyInfoController.java
...ehong/web/controller/equipment/TStoreyInfoController.java
+9
-0
TestTaskController.java
...m/zehong/web/controller/equipment/TestTaskController.java
+44
-32
AllCommandHandler.java
.../src/main/java/com/zehong/web/task/AllCommandHandler.java
+62
-0
PowerOffCommandEvent.java
...c/main/java/com/zehong/web/task/PowerOffCommandEvent.java
+29
-0
TStoreyInfo.java
...m/src/main/java/com/zehong/system/domain/TStoreyInfo.java
+22
-0
ModbusDeviceData.java
...ava/com/zehong/system/domain/modbus/ModbusDeviceData.java
+12
-0
TStoreyInfoMapper.java
...main/java/com/zehong/system/mapper/TStoreyInfoMapper.java
+2
-0
ITStoreyInfoService.java
...n/java/com/zehong/system/service/ITStoreyInfoService.java
+2
-0
TStoreyInfoServiceImpl.java
...om/zehong/system/service/impl/TStoreyInfoServiceImpl.java
+10
-0
TStoreyInfoMapper.xml
...em/src/main/resources/mapper/system/TStoreyInfoMapper.xml
+5
-1
storey.js
zhmes-agecal-web/src/api/storey/storey.js
+8
-0
AgingCabinetBoard.vue
...cal-web/src/views/screen/components/AgingCabinetBoard.vue
+13
-49
AgingLayer.vue
zhmes-agecal-web/src/views/screen/components/AgingLayer.vue
+265
-42
TrayBinding.vue
zhmes-agecal-web/src/views/screen/components/TrayBinding.vue
+544
-0
index.vue
zhmes-agecal-web/src/views/screen/index.vue
+54
-26
No files found.
zhmes-agecal-admin/src/main/java/com/zehong/web/controller/equipment/TStoreyInfoController.java
View file @
f8da175f
...
@@ -55,6 +55,15 @@ public class TStoreyInfoController extends BaseController
...
@@ -55,6 +55,15 @@ public class TStoreyInfoController extends BaseController
return
util
.
exportExcel
(
list
,
"老化层信息数据"
);
return
util
.
exportExcel
(
list
,
"老化层信息数据"
);
}
}
/**
* 获取老化层信息详细信息
*/
@GetMapping
(
value
=
"/queryByDepartmentId/{fEquipmentId}"
)
public
AjaxResult
queryByDepartmentId
(
@PathVariable
(
"fEquipmentId"
)
Long
fEquipmentId
)
{
return
AjaxResult
.
success
(
tStoreyInfoService
.
queryByDepartmentId
(
fEquipmentId
));
}
/**
/**
* 获取老化层信息详细信息
* 获取老化层信息详细信息
*/
*/
...
...
zhmes-agecal-admin/src/main/java/com/zehong/web/controller/equipment/TestTaskController.java
View file @
f8da175f
...
@@ -7,12 +7,16 @@ import com.serotonin.modbus4j.exception.ModbusTransportException;
...
@@ -7,12 +7,16 @@ import com.serotonin.modbus4j.exception.ModbusTransportException;
import
com.zehong.framework.modbus4j.Modbus4jUtils
;
import
com.zehong.framework.modbus4j.Modbus4jUtils
;
import
com.zehong.system.domain.TEquipmentAlarmData
;
import
com.zehong.system.domain.TEquipmentAlarmData
;
import
com.zehong.system.domain.TEquipmentInfo
;
import
com.zehong.system.domain.TEquipmentInfo
;
import
com.zehong.system.domain.TStoreyInfo
;
import
com.zehong.system.domain.modbus.ModbusDeviceData
;
import
com.zehong.system.domain.modbus.ModbusDeviceData
;
import
com.zehong.system.service.ITEquipmentAlarmDataService
;
import
com.zehong.system.service.ITEquipmentAlarmDataService
;
import
com.zehong.system.service.ITEquipmentInfoService
;
import
com.zehong.system.service.ITEquipmentInfoService
;
import
com.zehong.system.service.ITStoreyInfoService
;
import
com.zehong.web.task.AgingCabinetInspectionAndPowerCheckTask
;
import
com.zehong.web.task.AgingCabinetInspectionAndPowerCheckTask
;
import
com.zehong.web.task.PowerOffCommandEvent
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.context.ApplicationEventPublisher
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
...
@@ -42,6 +46,9 @@ public class TestTaskController {
...
@@ -42,6 +46,9 @@ public class TestTaskController {
@Resource
@Resource
private
ITEquipmentAlarmDataService
tEquipmentAlarmDataService
;
private
ITEquipmentAlarmDataService
tEquipmentAlarmDataService
;
@Resource
private
ApplicationEventPublisher
eventPublisher
;
// 新增事件发布器
/**
/**
* 五分钟一次
* 五分钟一次
* 1.老化柜、标定柜巡查
* 1.老化柜、标定柜巡查
...
@@ -80,16 +87,14 @@ public class TestTaskController {
...
@@ -80,16 +87,14 @@ public class TestTaskController {
}
}
List
<
CompletableFuture
<
ModbusDeviceData
>>
futures
=
equipmentInfos
.
stream
().
map
(
equipmentInfo
->
CompletableFuture
.
supplyAsync
(()
->
{
List
<
CompletableFuture
<
ModbusDeviceData
>>
futures
=
equipmentInfos
.
stream
().
map
(
equipmentInfo
->
CompletableFuture
.
supplyAsync
(()
->
{
ModbusMaster
master
=
null
;
ModbusMaster
master
=
null
;
// 构造结果对象
ModbusDeviceData
deviceData
;
// 10 层
// 10 层
List
<
Integer
>
registerOffsets
=
Arrays
.
asList
(
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
);
List
<
Integer
>
registerOffsets
=
Arrays
.
asList
(
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
);
try
{
try
{
master
=
Modbus4jUtils
.
getMaster
(
equipmentInfo
.
getfIp
(),
equipmentInfo
.
getfPort
());
master
=
Modbus4jUtils
.
getMaster
(
equipmentInfo
.
getfIp
(),
equipmentInfo
.
getfPort
());
Map
<
Integer
,
Object
>
integerObjectMap
=
Modbus4jUtils
.
batchReadAgingCabinetStatus
(
master
,
registerOffsets
);
Map
<
Integer
,
Object
>
integerObjectMap
=
Modbus4jUtils
.
batchReadAgingCabinetStatus
(
master
,
registerOffsets
);
// 返回结果
// 返回结果
无错误
return
createErrorData
(
equipmentInfo
,
""
,
""
,
integerObjectMap
);
return
createErrorData
(
equipmentInfo
,
""
,
""
,
integerObjectMap
);
}
catch
(
ModbusInitException
e
)
{
}
catch
(
ModbusInitException
e
)
{
// 记录异常数据
// 记录异常数据
...
@@ -104,16 +109,16 @@ public class TestTaskController {
...
@@ -104,16 +109,16 @@ public class TestTaskController {
// 返回错误信息
// 返回错误信息
Map
<
Integer
,
Object
>
errorMap
=
new
HashMap
<>();
Map
<
Integer
,
Object
>
errorMap
=
new
HashMap
<>();
// 返回结果
// 返回结果
return
createErrorData
(
equipmentInfo
,
"2"
,
"Modbus初始化失败"
,
errorMap
);
return
createErrorData
(
equipmentInfo
,
"2"
,
"Modbus初始化失败"
,
errorMap
);
// 层有错误返回 柜可能连不上也在这个报错里面
// 层有错误返回 柜可能连不上也在这个报错里面
}
catch
(
ModbusTransportException
e
)
{
}
catch
(
ModbusTransportException
e
)
{
// 网线没插好通讯不上
// 网线没插好通讯不上
if
(
e
.
getMessage
().
equals
(
"java.net.SocketTimeoutException: connect timed out"
))
{
if
(
e
.
getMessage
().
equals
(
"java.net.SocketTimeoutException: connect timed out"
))
{
// 记录异常数据
// 记录异常数据
alarmData
.
setfAlarmType
(
"01"
);
//01.老化柜 02.机械臂 03.老化层 04.点位
alarmData
.
setfAlarmType
(
"01"
);
//01.老化柜 02.机械臂 03.老化层 04.点位
alarmData
.
setfEquipmentCode
(
equipmentInfo
.
getfEquipmentCode
());
alarmData
.
setfEquipmentCode
(
equipmentInfo
.
getfEquipmentCode
());
alarmData
.
setfAlarmData
(
"定时任务巡检:老化柜网线没插好"
);
alarmData
.
setfAlarmData
(
"定时任务巡检:老化柜网线没插好"
);
// 线接错误
// 线接错误
}
else
{
}
else
{
// 记录异常数据
// 记录异常数据
alarmData
.
setfAlarmType
(
"01"
);
//01.老化柜 02.机械臂 03.老化层 04.点位
alarmData
.
setfAlarmType
(
"01"
);
//01.老化柜 02.机械臂 03.老化层 04.点位
...
@@ -128,17 +133,17 @@ public class TestTaskController {
...
@@ -128,17 +133,17 @@ public class TestTaskController {
Map
<
Integer
,
Object
>
errorMap
=
new
HashMap
<>();
Map
<
Integer
,
Object
>
errorMap
=
new
HashMap
<>();
// 网线没插好通讯不上
// 网线没插好通讯不上
// 返回结果
// 返回结果
if
(
e
.
getMessage
().
equals
(
"java.net.SocketTimeoutException: connect timed out"
))
{
if
(
e
.
getMessage
().
equals
(
"java.net.SocketTimeoutException: connect timed out"
))
{
return
createErrorData
(
equipmentInfo
,
"2"
,
"网线没插好"
,
errorMap
);
return
createErrorData
(
equipmentInfo
,
"2"
,
"定时任务巡检:网线没插好"
,
errorMap
);
}
else
{
}
else
{
// 线接错误
// 线接错误
// 返回结果
// 返回结果
return
createErrorData
(
equipmentInfo
,
"2"
,
"通信线路没接好"
,
errorMap
);
return
createErrorData
(
equipmentInfo
,
"2"
,
"定时任务巡检:通信线路没接好"
,
errorMap
);
}
}
}
catch
(
ErrorResponseException
e
)
{
}
catch
(
ErrorResponseException
e
)
{
Map
<
Integer
,
Object
>
errorMap
=
new
HashMap
<>();
Map
<
Integer
,
Object
>
errorMap
=
new
HashMap
<>();
// 返回结果
// 返回结果
return
createErrorData
(
equipmentInfo
,
"2"
,
"ErrorResponseException"
,
errorMap
);
return
createErrorData
(
equipmentInfo
,
"2"
,
"定时任务巡检:ErrorResponseException"
,
errorMap
);
}
finally
{
}
finally
{
if
(
master
!=
null
)
{
if
(
master
!=
null
)
{
master
.
destroy
();
master
.
destroy
();
...
@@ -168,15 +173,16 @@ public class TestTaskController {
...
@@ -168,15 +173,16 @@ public class TestTaskController {
return
deferredResult
;
return
deferredResult
;
}
}
private
ModbusDeviceData
createErrorData
(
TEquipmentInfo
equipmentInfo
,
String
status
,
private
ModbusDeviceData
createErrorData
(
TEquipmentInfo
equipmentInfo
,
String
status
,
String
errorReason
,
Map
<
Integer
,
Object
>
integerObjectMap
)
{
String
errorReason
,
Map
<
Integer
,
Object
>
integerObjectMap
)
{
ModbusDeviceData
deviceData
=
new
ModbusDeviceData
();
ModbusDeviceData
deviceData
=
new
ModbusDeviceData
();
deviceData
.
setId
(
equipmentInfo
.
getfEquipmentId
());
deviceData
.
setfIp
(
equipmentInfo
.
getfIp
());
deviceData
.
setfIp
(
equipmentInfo
.
getfIp
());
deviceData
.
setfPort
(
equipmentInfo
.
getfPort
());
deviceData
.
setfPort
(
equipmentInfo
.
getfPort
());
deviceData
.
setDeviceCode
(
equipmentInfo
.
getfEquipmentCode
());
deviceData
.
setDeviceCode
(
equipmentInfo
.
getfEquipmentCode
());
deviceData
.
setDeviceStatus
(
status
);
deviceData
.
setDeviceStatus
(
status
);
deviceData
.
setErrorReason
(
errorReason
);
deviceData
.
setErrorReason
(
errorReason
);
if
(
integerObjectMap
!=
null
)
{
if
(
integerObjectMap
!=
null
)
{
deviceData
.
setRegisterValues
(
integerObjectMap
.
entrySet
().
stream
()
deviceData
.
setRegisterValues
(
integerObjectMap
.
entrySet
().
stream
()
.
collect
(
Collectors
.
toMap
(
.
collect
(
Collectors
.
toMap
(
Map
.
Entry
::
getKey
,
Map
.
Entry
::
getKey
,
...
@@ -188,28 +194,34 @@ public class TestTaskController {
...
@@ -188,28 +194,34 @@ public class TestTaskController {
// 处理 老化柜 是 运行 开始 空闲
// 处理 老化柜 是 运行 开始 空闲
private
List
<
ModbusDeviceData
>
processDeviceData
(
List
<
ModbusDeviceData
>
deviceDataList
)
{
private
List
<
ModbusDeviceData
>
processDeviceData
(
List
<
ModbusDeviceData
>
deviceDataList
)
{
for
(
ModbusDeviceData
modbusDeviceData
:
deviceDataList
)
{
for
(
ModbusDeviceData
modbusDeviceData
:
deviceDataList
)
{
Map
<
Integer
,
String
>
registerValues
=
modbusDeviceData
.
getRegisterValues
();
Map
<
Integer
,
String
>
registerValues
=
modbusDeviceData
.
getRegisterValues
();
boolean
isRun
=
false
;
// 大于0 说明 柜能通信;小于0 说明柜 不能通信
for
(
Map
.
Entry
<
Integer
,
String
>
entry
:
registerValues
.
entrySet
())
{
if
(
registerValues
.
size
()
>
0
)
{
Integer
registerOffset
=
entry
.
getKey
();
boolean
isRun
=
false
;
String
registerValue
=
entry
.
getValue
();
for
(
Map
.
Entry
<
Integer
,
String
>
entry
:
registerValues
.
entrySet
())
{
if
(
"true"
.
equals
(
registerValue
))
{
Integer
registerOffset
=
entry
.
getKey
();
isRun
=
true
;
String
registerValue
=
entry
.
getValue
();
// 要给这个 层 发断电的 指令
if
(
"true"
.
equals
(
registerValue
))
{
}
else
{
isRun
=
true
;
try
{
// 要给这个 层 发断电的 指令
ModbusMaster
master
=
Modbus4jUtils
.
getMaster
(
modbusDeviceData
.
getfIp
(),
modbusDeviceData
.
getfPort
());
}
else
{
Modbus4jUtils
.
writeCoil
(
master
,
1
,
registerOffset
,
false
);
// 发布断电指令事件(不再直接执行)
}
catch
(
ModbusInitException
|
ModbusTransportException
e
)
{
eventPublisher
.
publishEvent
(
new
PowerOffCommandEvent
(
throw
new
RuntimeException
(
e
);
this
,
modbusDeviceData
.
getDeviceCode
(),
modbusDeviceData
.
getfIp
(),
modbusDeviceData
.
getfPort
(),
registerOffset
));
}
}
}
}
}
if
(
isRun
)
{
if
(
isRun
)
{
modbusDeviceData
.
setDeviceStatus
(
"1"
);
modbusDeviceData
.
setDeviceStatus
(
"1"
);
}
else
{
}
else
{
modbusDeviceData
.
setDeviceStatus
(
"0"
);
modbusDeviceData
.
setDeviceStatus
(
"0"
);
}
}
}
}
}
return
deviceDataList
;
return
deviceDataList
;
...
...
zhmes-agecal-admin/src/main/java/com/zehong/web/task/AllCommandHandler.java
0 → 100644
View file @
f8da175f
package
com
.
zehong
.
web
.
task
;
import
com.serotonin.modbus4j.ModbusMaster
;
import
com.serotonin.modbus4j.exception.ModbusInitException
;
import
com.serotonin.modbus4j.exception.ModbusTransportException
;
import
com.zehong.framework.modbus4j.Modbus4jUtils
;
import
com.zehong.system.domain.TEquipmentAlarmData
;
import
com.zehong.system.domain.TStoreyInfo
;
import
com.zehong.system.service.ITEquipmentAlarmDataService
;
import
com.zehong.system.service.ITStoreyInfoService
;
import
org.springframework.context.event.EventListener
;
import
org.springframework.scheduling.annotation.Async
;
import
org.springframework.stereotype.Component
;
import
javax.annotation.Resource
;
/**
* @author lenovo
* @date 2025/6/17
* @description TODO
*/
@Component
public
class
AllCommandHandler
{
private
static
final
org
.
slf4j
.
Logger
log
=
org
.
slf4j
.
LoggerFactory
.
getLogger
(
AllCommandHandler
.
class
);
@Resource
private
ITEquipmentAlarmDataService
alarmDataService
;
@Resource
private
ITStoreyInfoService
tStoreyInfoService
;
@Async
// 异步执行
@EventListener
(
PowerOffCommandEvent
.
class
)
public
void
handlePowerOffCommand
(
PowerOffCommandEvent
event
)
{
try
{
String
storeyCode
=
event
.
getDeviceCode
()
+
"-"
+
event
.
getLayer
();
log
.
info
(
"需要发送断电指令 - 设备:{} 层:{}"
,
event
.
getDeviceCode
(),
event
.
getLayer
());
TStoreyInfo
tStoreyInfo
=
tStoreyInfoService
.
selectTStoreyInfoByCode
(
storeyCode
);
if
(
tStoreyInfo
==
null
)
{
TEquipmentAlarmData
alarmData
=
new
TEquipmentAlarmData
();
// 记录异常数据
alarmData
.
setfAlarmType
(
"01"
);
//01.老化柜 02.机械臂 03.老化层 04.点位
alarmData
.
setfEquipmentCode
(
event
.
getDeviceCode
());
alarmData
.
setfAlarmData
(
"下属"
+
storeyCode
+
"号老化层不存在"
);
alarmDataService
.
insertTEquipmentAlarmData
(
alarmData
);
}
else
{
ModbusMaster
master
=
Modbus4jUtils
.
getMaster
(
tStoreyInfo
.
getfIp
(),
tStoreyInfo
.
getfPort
());
Modbus4jUtils
.
writeCoil
(
master
,
1
,
event
.
getLayer
(),
false
);
log
.
info
(
"已发送断电指令 - 设备:{} 层:{}"
,
event
.
getDeviceCode
(),
event
.
getLayer
());
master
.
destroy
();
}
}
catch
(
ModbusInitException
|
ModbusTransportException
e
)
{
log
.
error
(
"断电指令执行失败 - 设备:{} 层:{}"
,
event
.
getDeviceCode
(),
event
.
getLayer
(),
e
);
// 记录异常
TEquipmentAlarmData
alarmData
=
new
TEquipmentAlarmData
();
alarmData
.
setfAlarmType
(
"03"
);
// 老化层
alarmData
.
setfEquipmentCode
(
event
.
getDeviceCode
());
alarmData
.
setfAlarmData
(
"断电指令执行失败: "
+
e
.
getMessage
());
alarmDataService
.
insertTEquipmentAlarmData
(
alarmData
);
}
}
}
zhmes-agecal-admin/src/main/java/com/zehong/web/task/PowerOffCommandEvent.java
0 → 100644
View file @
f8da175f
package
com
.
zehong
.
web
.
task
;
import
org.springframework.context.ApplicationEvent
;
/**
* @author lenovo
* @date 2025/6/17
* @description 断电event
*/
public
class
PowerOffCommandEvent
extends
ApplicationEvent
{
private
final
String
ip
;
private
final
int
port
;
private
final
int
layer
;
private
final
String
deviceCode
;
public
PowerOffCommandEvent
(
Object
source
,
String
deviceCode
,
String
ip
,
int
port
,
int
layer
)
{
super
(
source
);
this
.
deviceCode
=
deviceCode
;
this
.
ip
=
ip
;
this
.
port
=
port
;
this
.
layer
=
layer
;
}
// Getters
public
String
getIp
()
{
return
ip
;
}
public
int
getPort
()
{
return
port
;
}
public
int
getLayer
()
{
return
layer
;
}
public
String
getDeviceCode
()
{
return
deviceCode
;
}
}
zhmes-agecal-system/src/main/java/com/zehong/system/domain/TStoreyInfo.java
View file @
f8da175f
package
com
.
zehong
.
system
.
domain
;
package
com
.
zehong
.
system
.
domain
;
import
java.util.Date
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.Map
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
org.apache.commons.lang3.builder.ToStringBuilder
;
import
org.apache.commons.lang3.builder.ToStringBuilder
;
import
org.apache.commons.lang3.builder.ToStringStyle
;
import
org.apache.commons.lang3.builder.ToStringStyle
;
...
@@ -17,6 +20,14 @@ public class TStoreyInfo extends BaseEntity
...
@@ -17,6 +20,14 @@ public class TStoreyInfo extends BaseEntity
{
{
private
static
final
long
serialVersionUID
=
1L
;
private
static
final
long
serialVersionUID
=
1L
;
/**状态*/
private
static
Map
<
String
,
String
>
statusStrMap
=
new
HashMap
<
String
,
String
>(){{
put
(
"0"
,
"空闲"
);
put
(
"1"
,
"运行"
);
put
(
"2"
,
"故障"
);
put
(
"3"
,
"断电"
);
}};
/** 层ID */
/** 层ID */
private
Long
fStoreyId
;
private
Long
fStoreyId
;
...
@@ -40,6 +51,8 @@ public class TStoreyInfo extends BaseEntity
...
@@ -40,6 +51,8 @@ public class TStoreyInfo extends BaseEntity
@Excel
(
name
=
"状态:0空闲,1运行,2故障,3断电"
)
@Excel
(
name
=
"状态:0空闲,1运行,2故障,3断电"
)
private
String
fStatus
;
private
String
fStatus
;
private
String
statusStr
;
/** 老化开始时间 */
/** 老化开始时间 */
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
)
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
)
@Excel
(
name
=
"更新时间"
,
width
=
30
,
dateFormat
=
"yyyy-MM-dd HH:mm:ss"
)
@Excel
(
name
=
"更新时间"
,
width
=
30
,
dateFormat
=
"yyyy-MM-dd HH:mm:ss"
)
...
@@ -106,6 +119,15 @@ public class TStoreyInfo extends BaseEntity
...
@@ -106,6 +119,15 @@ public class TStoreyInfo extends BaseEntity
{
{
return
fStatus
;
return
fStatus
;
}
}
public
String
getStatusStr
()
{
return
statusStrMap
.
get
(
fStatus
);
}
public
void
setStatusStr
(
String
statusStr
)
{
this
.
statusStr
=
statusStr
;
}
public
void
setfPort
(
Integer
fPort
)
public
void
setfPort
(
Integer
fPort
)
{
{
this
.
fPort
=
fPort
;
this
.
fPort
=
fPort
;
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/domain/modbus/ModbusDeviceData.java
View file @
f8da175f
...
@@ -8,6 +8,10 @@ import java.util.Map;
...
@@ -8,6 +8,10 @@ import java.util.Map;
* @description modbus设备数据
* @description modbus设备数据
*/
*/
public
class
ModbusDeviceData
{
public
class
ModbusDeviceData
{
// equipmentId
private
Long
id
;
private
String
deviceCode
;
private
String
deviceCode
;
/** IP地址 */
/** IP地址 */
...
@@ -75,4 +79,12 @@ public class ModbusDeviceData {
...
@@ -75,4 +79,12 @@ public class ModbusDeviceData {
public
void
setfPort
(
Integer
fPort
)
{
public
void
setfPort
(
Integer
fPort
)
{
this
.
fPort
=
fPort
;
this
.
fPort
=
fPort
;
}
}
public
Long
getId
()
{
return
id
;
}
public
void
setId
(
Long
id
)
{
this
.
id
=
id
;
}
}
}
zhmes-agecal-system/src/main/java/com/zehong/system/mapper/TStoreyInfoMapper.java
View file @
f8da175f
...
@@ -35,6 +35,8 @@ public interface TStoreyInfoMapper
...
@@ -35,6 +35,8 @@ public interface TStoreyInfoMapper
*/
*/
public
List
<
TStoreyInfo
>
selectTStoreyInfoList
(
TStoreyInfo
tStoreyInfo
);
public
List
<
TStoreyInfo
>
selectTStoreyInfoList
(
TStoreyInfo
tStoreyInfo
);
public
List
<
TStoreyInfo
>
queryByDepartmentId
(
Long
fEquipmentId
);
/**
/**
* 新增老化层信息
* 新增老化层信息
*
*
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/service/ITStoreyInfoService.java
View file @
f8da175f
...
@@ -35,6 +35,8 @@ public interface ITStoreyInfoService
...
@@ -35,6 +35,8 @@ public interface ITStoreyInfoService
*/
*/
public
List
<
TStoreyInfo
>
selectTStoreyInfoList
(
TStoreyInfo
tStoreyInfo
);
public
List
<
TStoreyInfo
>
selectTStoreyInfoList
(
TStoreyInfo
tStoreyInfo
);
public
List
<
TStoreyInfo
>
queryByDepartmentId
(
Long
fDepartmentId
);
/**
/**
* 新增老化层信息
* 新增老化层信息
*
*
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/service/impl/TStoreyInfoServiceImpl.java
View file @
f8da175f
...
@@ -55,6 +55,16 @@ public class TStoreyInfoServiceImpl implements ITStoreyInfoService
...
@@ -55,6 +55,16 @@ public class TStoreyInfoServiceImpl implements ITStoreyInfoService
return
tStoreyInfoMapper
.
selectTStoreyInfoList
(
tStoreyInfo
);
return
tStoreyInfoMapper
.
selectTStoreyInfoList
(
tStoreyInfo
);
}
}
/**
* 根据设备id 查询层信息
* @param fEquipmentId f
* @return r
*/
@Override
public
List
<
TStoreyInfo
>
queryByDepartmentId
(
Long
fEquipmentId
)
{
return
tStoreyInfoMapper
.
queryByDepartmentId
(
fEquipmentId
);
}
/**
/**
* 新增老化层信息
* 新增老化层信息
*
*
...
...
zhmes-agecal-system/src/main/resources/mapper/system/TStoreyInfoMapper.xml
View file @
f8da175f
...
@@ -18,7 +18,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
...
@@ -18,7 +18,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
</resultMap>
<sql
id=
"selectTStoreyInfoVo"
>
<sql
id=
"selectTStoreyInfoVo"
>
select f_storey_id, f_equipment_id, f_storey_code, f_
tray_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 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
</sql>
</sql>
<select
id=
"selectTStoreyInfoList"
parameterType=
"TStoreyInfo"
resultMap=
"TStoreyInfoResult"
>
<select
id=
"selectTStoreyInfoList"
parameterType=
"TStoreyInfo"
resultMap=
"TStoreyInfoResult"
>
...
@@ -34,6 +34,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
...
@@ -34,6 +34,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if
test=
"fAlarmTime != null "
>
and f_alarm_time = #{fAlarmTime}
</if>
<if
test=
"fAlarmTime != null "
>
and f_alarm_time = #{fAlarmTime}
</if>
</where>
</where>
</select>
</select>
<select
id=
"queryByDepartmentId"
parameterType=
"long"
resultMap=
"TStoreyInfoResult"
>
<include
refid=
"selectTStoreyInfoVo"
/>
where f_equipment_id = #{fEquipmentId}
</select>
<select
id=
"selectTStoreyInfoById"
parameterType=
"Long"
resultMap=
"TStoreyInfoResult"
>
<select
id=
"selectTStoreyInfoById"
parameterType=
"Long"
resultMap=
"TStoreyInfoResult"
>
<include
refid=
"selectTStoreyInfoVo"
/>
<include
refid=
"selectTStoreyInfoVo"
/>
...
...
zhmes-agecal-web/src/api/storey/storey.js
View file @
f8da175f
...
@@ -9,6 +9,14 @@ export function listStorey(query) {
...
@@ -9,6 +9,14 @@ export function listStorey(query) {
})
})
}
}
// 根据设备id查询老化层信息列表
export
function
queryByDepartmentId
(
fDepartmentId
)
{
return
request
({
url
:
'/storey/queryByDepartmentId/'
+
fDepartmentId
,
method
:
'get'
})
}
// 查询老化层信息详细
// 查询老化层信息详细
export
function
getStorey
(
fStoreyId
)
{
export
function
getStorey
(
fStoreyId
)
{
return
request
({
return
request
({
...
...
zhmes-agecal-web/src/views/screen/components/AgingCabinetBoard.vue
View file @
f8da175f
...
@@ -29,7 +29,7 @@
...
@@ -29,7 +29,7 @@
placement=
"top"
placement=
"top"
>
>
<el-card
<el-card
:class=
"statusMap[item.
s
tatus]"
:class=
"statusMap[item.
deviceS
tatus]"
style=
"
style=
"
width: 150px;
width: 150px;
height: 150px;
height: 150px;
...
@@ -59,49 +59,13 @@ export default {
...
@@ -59,49 +59,13 @@ export default {
return
{
return
{
// 示例数据格式,实际从后端获取
// 示例数据格式,实际从后端获取
cabinets
:
[
cabinets
:
[
{
id
:
1
,
status
:
'available'
},
{
id
:
2
,
status
:
'occupied'
},
{
id
:
3
,
status
:
'default'
},
{
id
:
4
,
status
:
'default'
},
{
id
:
5
,
status
:
'default'
},
{
id
:
6
,
status
:
'default'
},
{
id
:
7
,
status
:
'default'
},
{
id
:
8
,
status
:
'default'
},
{
id
:
9
,
status
:
'default'
},
{
id
:
10
,
status
:
'default'
},
{
id
:
11
,
status
:
'default'
},
{
id
:
12
,
status
:
'default'
},
{
id
:
13
,
status
:
'default'
},
{
id
:
14
,
status
:
'default'
},
{
id
:
15
,
status
:
'default'
},
{
id
:
16
,
status
:
'default'
},
{
id
:
17
,
status
:
'default'
},
{
id
:
18
,
status
:
'default'
},
{
id
:
19
,
status
:
'default'
},
{
id
:
20
,
status
:
'default'
},
{
id
:
21
,
status
:
'default'
},
{
id
:
22
,
status
:
'default'
},
{
id
:
23
,
status
:
'default'
},
{
id
:
24
,
status
:
'default'
},
{
id
:
25
,
status
:
'default'
},
{
id
:
26
,
status
:
'default'
},
{
id
:
27
,
status
:
'default'
},
{
id
:
28
,
status
:
'default'
},
{
id
:
29
,
status
:
'default'
},
{
id
:
30
,
status
:
'default'
},
{
id
:
31
,
status
:
'default'
},
{
id
:
32
,
status
:
'default'
},
{
id
:
33
,
status
:
'default'
},
{
id
:
34
,
status
:
'default'
},
{
id
:
35
,
status
:
'default'
},
{
id
:
36
,
status
:
'default'
},
// ...共36个
// ...共36个
],
],
// 状态对应的颜色类名
// 状态对应的颜色类名
statusMap
:
{
statusMap
:
{
default
:
'default'
,
0
:
'default'
,
available
:
'available'
,
1
:
'available'
,
occupied
:
'occupied'
2
:
'occupied'
},
},
agingCabinetList
:
null
agingCabinetList
:
null
};
};
...
@@ -118,27 +82,27 @@ export default {
...
@@ -118,27 +82,27 @@ export default {
}
}
},
},
mounted
()
{
mounted
()
{
this
.
testAgingCabinetAndPowerCheck
();
//this.testAgingCabinetAndPowerCheck();
},
},
methods
:
{
methods
:
{
handleCardClick
(
item
)
{
handleCardClick
(
item
)
{
this
.
msgSuccess
(
"你想看层信息是吧"
);
// 触发事件传递 cabinetId 给父组件
this
.
$emit
(
'cabinet-click'
,
item
);
},
},
getTooltipContent
(
item
)
{
getTooltipContent
(
item
)
{
switch
(
item
.
s
tatus
)
{
switch
(
item
.
deviceS
tatus
)
{
case
'
occupied
'
:
case
'
2
'
:
return
item
.
fault
Reason
||
'无故障详情'
;
return
item
.
error
Reason
||
'无故障详情'
;
case
'
available
'
:
case
'
1
'
:
return
'运行中'
;
return
'运行中'
;
case
'
default
'
:
case
'
0
'
:
default
:
default
:
return
'空闲'
;
return
'空闲'
;
}
}
},
},
testAgingCabinetAndPowerCheck
()
{
testAgingCabinetAndPowerCheck
()
{
getAgingCabinetAndPowerCheck
().
then
(
response
=>
{
getAgingCabinetAndPowerCheck
().
then
(
response
=>
{
this
.
agingCabinetList
=
response
;
this
.
cabinets
=
response
;
}
}
);
);
}
}
...
...
zhmes-agecal-web/src/views/screen/components/AgingLayer.vue
View file @
f8da175f
<
template
>
<
template
>
<div
class=
"screen-container"
>
<div
class=
"screen-container"
>
<!-- 返回按钮 -->
<div
class=
"back-button"
@
click=
"goBack"
>
<i
class=
"el-icon-back"
></i>
返回老化柜看板
</div>
<!-- 整体容器 -->
<!-- 整体容器 -->
<div
class=
"content-container"
>
<div
class=
"content-container"
>
<!-- 柜体容器 -->
<!-- 柜体容器 -->
<div
class=
"cabinet-body"
>
<div
class=
"cabinet-body"
>
<!-- 标题 -->
<!-- 标题 -->
<div
class=
"title"
ref=
"title"
>
2
号柜
</div>
<div
class=
"title"
ref=
"title"
>
{{
modbusDeviceData
.
id
}}
号柜
</div>
<div
class=
"cabinet-and-lines"
>
<div
class=
"cabinet-and-lines"
>
<!-- 柜体 -->
<!-- 柜体 -->
<div
class=
"cabinet"
ref=
"cabinetContainer"
>
<div
class=
"cabinet"
ref=
"cabinetContainer"
>
<div
<div
v-for=
"(layer, index) in layers"
v-for=
"(layer, index) in layers"
:key=
"layer.
name
"
:key=
"layer.
id
"
class=
"layer"
class=
"layer"
:style=
"getLayerStyle(index)"
:style=
"getLayerStyle(index)"
:class=
"['layer-depth', `layer-$
{index}`]"
:class=
"[
'layer-depth',
`layer-$
{index}`,
getStatusClass(layer.fStatus) // 动态状态类
]"
@click="selectLayer(index)"
@click="selectLayer(index)"
>
>
{{
layer
.
name
}}
<div
class=
"layer-content"
>
<div
class=
"layer-name"
>
{{
layer
.
name
}}
</div>
<div
class=
"layer-status"
>
{{
getStatusText
(
layer
.
fStatus
)
}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -32,29 +44,32 @@
...
@@ -32,29 +44,32 @@
<!-- 托盘信息展示区域 -->
<!-- 托盘信息展示区域 -->
<div
class=
"tray-header"
>
<div
class=
"tray-header"
>
<span
class=
"tray-label"
>
托盘
</span>
<span
class=
"tray-label"
>
托盘
</span>
<span
class=
"tray-id"
>
TP-
{{
trayInfo
.
id
}}
</span>
<span
class=
"tray-id"
>
TP-
{{
trayInfo
.
id
||
'--'
}}
</span>
</div>
</div>
<div
class=
"tray-info"
>
<div
class=
"tray-info"
>
<div
class=
"info-row"
>
<div
class=
"info-row"
>
<div
class=
"info-label"
>
所在柜体:
</div>
<div
class=
"info-label"
>
所在柜体:
</div>
<div
class=
"info-value"
>
2号柜 -
{{
trayInfo
.
layer
}}
</div>
<div
class=
"info-value"
>
{{
modbusDeviceData
.
id
}}
号柜 -
{{
trayInfo
.
layer
.
split
(
"-"
)[
1
]
||
'--'
}}
层
</div>
</div>
</div>
<div
class=
"info-row"
>
<div
class=
"info-row"
>
<div
class=
"info-label"
>
产品型号:
</div>
<div
class=
"info-label"
>
产品型号:
</div>
<div
class=
"info-value"
>
{{
trayInfo
.
productModel
}}
</div>
<div
class=
"info-value"
>
{{
trayInfo
.
productModel
||
'--'
}}
</div>
</div>
</div>
<div
class=
"info-row"
>
<div
class=
"info-row"
>
<div
class=
"info-label"
>
当前状态:
</div>
<div
class=
"info-label"
>
当前状态:
</div>
<div
class=
"info-value"
:class=
"trayInfo.statusClass"
>
{{
trayInfo
.
status
}}
</div>
<div
class=
"info-value"
:class=
"trayInfo.statusClass || 'status-idle'"
>
{{
trayInfo
.
status
||
'--'
}}
</div>
</div>
</div>
<div
class=
"info-row"
>
<div
class=
"info-row"
>
<div
class=
"info-label"
>
老化
时长
:
</div>
<div
class=
"info-label"
>
老化
开始时间
:
</div>
<div
class=
"info-value"
>
{{
trayInfo
.
agingTime
}}
小时
</div>
<div
class=
"info-value"
>
{{
formatDateTime
(
trayInfo
.
fAgingStartTime
)
||
'--'
}}
</div>
</div>
</div>
<div
class=
"info-row"
>
<div
class=
"info-row"
>
<div
class=
"info-label"
>
温度
:
</div>
<div
class=
"info-label"
>
老化时长
:
</div>
<div
class=
"info-value
"
>
{{
trayInfo
.
temperature
}}
°C
</div>
<div
class=
"info-value
aging-time"
>
{{
agingTimeDisplay
}}
</div>
</div>
</div>
</div>
</div>
...
@@ -75,43 +90,181 @@
...
@@ -75,43 +90,181 @@
</
template
>
</
template
>
<
script
>
<
script
>
import
{
queryByDepartmentId
}
from
"@/api/storey/storey"
;
export
default
{
export
default
{
name
:
"AgingLayer"
,
name
:
"AgingLayer"
,
props
:
{
modbusDeviceData
:
{
type
:
Object
,
default
:
()
=>
({})
}
},
data
()
{
data
()
{
return
{
return
{
layers
:
Array
.
from
({
length
:
10
},
(
_
,
i
)
=>
({
layers
:
[],
name
:
`第
${
i
+
1
}
层`
,
trayInfo
:
{},
})),
agingTimer
:
null
,
trayInfo
:
{
agingStartTime
:
null
,
id
:
"202307-015"
,
agingTimeDisplay
:
"00:00:00"
layer
:
"第3层"
,
productModel
:
"PQC-1002"
,
status
:
"运行中"
,
statusClass
:
"status-running"
,
agingTime
:
"24"
,
temperature
:
"65"
,
},
};
};
},
},
watch
:
{
modbusDeviceData
:
{
immediate
:
true
,
handler
(
newVal
)
{
if
(
newVal
&&
newVal
.
id
)
{
this
.
loadCabinetData
(
newVal
.
id
);
}
}
},
trayInfo
:
{
deep
:
true
,
handler
(
newVal
)
{
if
(
newVal
.
fAgingStartTime
)
{
this
.
startAgingTimer
(
newVal
.
fAgingStartTime
);
}
else
{
this
.
stopAgingTimer
();
this
.
agingTimeDisplay
=
"00:00:00"
;
}
}
}
},
mounted
()
{
if
(
this
.
modbusDeviceData
&&
this
.
modbusDeviceData
.
id
)
{
this
.
loadCabinetData
(
this
.
modbusDeviceData
.
id
);
}
},
beforeDestroy
()
{
this
.
stopAgingTimer
();
},
methods
:
{
methods
:
{
// 格式化日期时间
formatDateTime
(
dateString
)
{
if
(
!
dateString
)
return
"--"
;
const
date
=
new
Date
(
dateString
);
return
date
.
toLocaleString
(
'zh-CN'
,
{
year
:
'numeric'
,
month
:
'2-digit'
,
day
:
'2-digit'
,
hour
:
'2-digit'
,
minute
:
'2-digit'
,
second
:
'2-digit'
});
},
// 启动老化计时器
startAgingTimer
(
startTime
)
{
this
.
stopAgingTimer
();
this
.
agingStartTime
=
new
Date
(
startTime
);
// 立即更新一次
this
.
updateAgingTime
();
// 每秒更新一次
this
.
agingTimer
=
setInterval
(()
=>
{
this
.
updateAgingTime
();
},
1000
);
},
// 更新老化时间显示
updateAgingTime
()
{
if
(
!
this
.
agingStartTime
)
return
;
const
now
=
new
Date
();
const
diff
=
Math
.
floor
((
now
-
this
.
agingStartTime
)
/
1000
);
// 秒数
const
hours
=
Math
.
floor
(
diff
/
3600
);
const
minutes
=
Math
.
floor
((
diff
%
3600
)
/
60
);
const
seconds
=
diff
%
60
;
this
.
agingTimeDisplay
=
`
${
this
.
padZero
(
hours
)}
:
${
this
.
padZero
(
minutes
)}
:
${
this
.
padZero
(
seconds
)}
`
;
},
// 停止老化计时器
stopAgingTimer
()
{
if
(
this
.
agingTimer
)
{
clearInterval
(
this
.
agingTimer
);
this
.
agingTimer
=
null
;
}
},
// 数字补零
padZero
(
num
)
{
return
num
.
toString
().
padStart
(
2
,
'0'
);
},
// 加载柜子详情数据
loadCabinetData
(
id
)
{
queryByDepartmentId
(
id
).
then
(
res
=>
{
if
(
res
.
code
===
200
&&
res
.
data
.
length
>
0
)
{
this
.
layers
=
res
.
data
.
map
((
item
,
i
)
=>
({
...
item
,
name
:
item
.
fStoreyCode
,
id
:
item
.
fStoreyId
,
layer
:
item
.
fStoreyCode
,
productModel
:
`PQC-
${
1000
+
i
}
`
,
status
:
this
.
getStatusText
(
item
.
fStatus
),
statusClass
:
this
.
getStatusClass
(
item
.
fStatus
),
fAgingStartTime
:
item
.
fAgingStartTime
}));
// 默认选中第一层
if
(
this
.
layers
.
length
>
0
)
{
this
.
selectLayer
(
0
);
}
}
else
{
this
.
$message
.
error
(
"加载层数据失败"
);
console
.
error
(
"加载数据失败:"
,
res
.
message
);
}
}).
catch
(
error
=>
{
this
.
$message
.
error
(
"加载数据异常"
);
console
.
error
(
"加载数据异常:"
,
error
);
});
},
// 返回老化柜看板
goBack
()
{
this
.
$emit
(
'go-back'
);
},
// 选择层
selectLayer
(
index
)
{
selectLayer
(
index
)
{
// 模拟选择不同层时托盘信息的变化
this
.
trayInfo
=
{
...
this
.
layers
[
index
]
};
this
.
trayInfo
=
{
id
:
`202307-
${(
index
+
1
).
toString
().
padStart
(
3
,
'0'
)}
`
,
layer
:
this
.
layers
[
index
].
name
,
productModel
:
`PQC-
${
1000
+
index
}
`
,
status
:
index
%
3
===
0
?
"待机"
:
"运行中"
,
statusClass
:
index
%
3
===
0
?
"status-idle"
:
"status-running"
,
agingTime
:
(
24
+
index
).
toString
(),
temperature
:
(
65
+
index
).
toString
(),
};
},
},
// 操作按钮方法
loadTray
()
{
loadTray
()
{
this
.
$message
.
success
(
"上料操作已执行"
);
this
.
$message
.
success
(
"上料操作已执行"
);
},
},
powerOn
()
{
powerOn
()
{
this
.
$message
.
success
(
"上电操作已执行"
);
this
.
$message
.
success
(
"上电操作已执行"
);
},
},
// 获取状态类名
getStatusClass
(
status
)
{
switch
(
status
)
{
case
'0'
:
return
'status-idle'
;
case
'1'
:
return
'status-running'
;
case
'2'
:
return
'status-fault'
;
case
'3'
:
return
'status-power_outage'
;
default
:
return
'status-idle'
;
}
},
// 获取状态文本
getStatusText
(
status
)
{
switch
(
status
)
{
case
'0'
:
return
'空闲'
;
case
'1'
:
return
'运行中'
;
case
'2'
:
return
'故障'
;
case
'3'
:
return
'断电'
;
default
:
return
'未知状态'
;
}
},
// 获取层样式
getLayerStyle
(
index
)
{
getLayerStyle
(
index
)
{
const
verticalSpacing
=
70
;
const
verticalSpacing
=
70
;
return
{
return
{
...
@@ -120,12 +273,63 @@ export default {
...
@@ -120,12 +273,63 @@ export default {
height
:
'60px'
,
height
:
'60px'
,
zIndex
:
index
,
zIndex
:
index
,
};
};
}
,
}
}
}
};
};
</
script
>
</
script
>
<
style
scoped
>
<
style
scoped
>
/* 状态背景色 */
.status-idle
{
background
:
linear-gradient
(
to
bottom
,
rgba
(
255
,
255
,
255
,
0.15
),
rgba
(
0
,
0
,
0
,
0.2
));
border-color
:
rgba
(
100
,
180
,
255
,
0.6
)
!important
;
}
.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-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
;
}
.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
;
}
/* 层内容样式 */
.layer-content
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
width
:
100%
;
height
:
100%
;
}
.layer-name
{
font-size
:
16px
;
font-weight
:
bold
;
margin-bottom
:
4px
;
}
.layer-status
{
font-size
:
12px
;
opacity
:
0.9
;
}
/* 老化时间样式 */
.aging-time
{
font-family
:
'Courier New'
,
monospace
;
font-size
:
16px
;
letter-spacing
:
1px
;
color
:
#64ffaa
;
}
/* 其他样式保持不变(原有样式) */
.screen-container
{
.screen-container
{
color
:
white
;
color
:
white
;
font-family
:
'Arial'
,
sans-serif
;
font-family
:
'Arial'
,
sans-serif
;
...
@@ -139,7 +343,6 @@ export default {
...
@@ -139,7 +343,6 @@ export default {
background
:
radial-gradient
(
circle
at
center
,
#041740
0%
,
#030b2a
70%
);
background
:
radial-gradient
(
circle
at
center
,
#041740
0%
,
#030b2a
70%
);
}
}
/* 新增:内容容器 */
.content-container
{
.content-container
{
display
:
flex
;
display
:
flex
;
width
:
100%
;
width
:
100%
;
...
@@ -149,7 +352,6 @@ export default {
...
@@ -149,7 +352,6 @@ export default {
padding
:
0
50px
;
padding
:
0
50px
;
}
}
/* 柜体容器 - 使用Flexbox对齐 */
.cabinet-body
{
.cabinet-body
{
display
:
flex
;
display
:
flex
;
align-items
:
flex-start
;
align-items
:
flex-start
;
...
@@ -157,7 +359,6 @@ export default {
...
@@ -157,7 +359,6 @@ export default {
position
:
relative
;
position
:
relative
;
}
}
/* 标题样式 */
.title
{
.title
{
font-size
:
24px
;
font-size
:
24px
;
font-weight
:
bold
;
font-weight
:
bold
;
...
@@ -198,7 +399,6 @@ export default {
...
@@ -198,7 +399,6 @@ export default {
.layer
{
.layer
{
position
:
absolute
;
position
:
absolute
;
left
:
0
;
left
:
0
;
background
:
linear-gradient
(
to
bottom
,
rgba
(
255
,
255
,
255
,
0.15
),
rgba
(
0
,
0
,
0
,
0.2
));
border
:
1px
solid
rgba
(
100
,
180
,
255
,
0.6
);
border
:
1px
solid
rgba
(
100
,
180
,
255
,
0.6
);
box-shadow
:
box-shadow
:
0
4px
12px
rgba
(
0
,
0
,
0
,
0.6
),
0
4px
12px
rgba
(
0
,
0
,
0
,
0.6
),
...
@@ -229,7 +429,6 @@ export default {
...
@@ -229,7 +429,6 @@ export default {
rgba
(
100
,
180
,
255
,
0.4
);
rgba
(
100
,
180
,
255
,
0.4
);
}
}
/* 右侧内容区域 */
.right-content
{
.right-content
{
flex
:
1
;
flex
:
1
;
margin-left
:
80px
;
margin-left
:
80px
;
...
@@ -318,7 +517,7 @@ export default {
...
@@ -318,7 +517,7 @@ export default {
}
}
.info-label
{
.info-label
{
width
:
1
0
0px
;
width
:
1
3
0px
;
color
:
#64c8ff
;
color
:
#64c8ff
;
font-weight
:
bold
;
font-weight
:
bold
;
}
}
...
@@ -338,6 +537,16 @@ export default {
...
@@ -338,6 +537,16 @@ export default {
font-weight
:
bold
;
font-weight
:
bold
;
}
}
.status-fault
{
color
:
#ff3d3d
;
font-weight
:
bold
;
}
.status-power_outage
{
color
:
#9e9e9e
;
font-weight
:
bold
;
}
.tray-actions
{
.tray-actions
{
display
:
flex
;
display
:
flex
;
justify-content
:
flex-end
;
justify-content
:
flex-end
;
...
@@ -389,7 +598,6 @@ export default {
...
@@ -389,7 +598,6 @@ export default {
background-image
:
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M16 9v4.66l-3.5 3.51V19h-1v-1.83L8 13.65V9h8m0-6h-2v4h-4V3H8v4h-.01C6.9 6.99 6 7.89 6 8.98v5.52L9.5 18v3h5v-3l3.5-3.5V9c0-1.1-.9-2-2-2V3z'/%3E%3C/svg%3E")
;
background-image
:
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M16 9v4.66l-3.5 3.51V19h-1v-1.83L8 13.65V9h8m0-6h-2v4h-4V3H8v4h-.01C6.9 6.99 6 7.89 6 8.98v5.52L9.5 18v3h5v-3l3.5-3.5V9c0-1.1-.9-2-2-2V3z'/%3E%3C/svg%3E")
;
}
}
/* 添加光效 */
.glow-effect
{
.glow-effect
{
position
:
absolute
;
position
:
absolute
;
top
:
0
;
top
:
0
;
...
@@ -400,4 +608,19 @@ export default {
...
@@ -400,4 +608,19 @@ export default {
pointer-events
:
none
;
pointer-events
:
none
;
z-index
:
-1
;
z-index
:
-1
;
}
}
.back-button
{
cursor
:
pointer
;
margin-bottom
:
20px
;
width
:
145px
;
color
:
#409EFF
;
display
:
inline-flex
;
align-items
:
center
;
transition
:
all
0.3s
;
}
.back-button
:hover
{
color
:
#66b1ff
;
transform
:
translateX
(
-5px
);
}
</
style
>
</
style
>
zhmes-agecal-web/src/views/screen/components/TrayBinding.vue
0 → 100644
View file @
f8da175f
<
template
>
<div
class=
"tray-binding-container"
>
<!-- 头部区域 -->
<div
class=
"header"
>
<h1><i
class=
"fas fa-qrcode"
></i>
托盘数据绑定系统
</h1>
<p>
通过扫描枪扫描设备条码,自动将设备绑定到托盘指定位置
</p>
</div>
<!-- 托盘ID绑定区域 -->
<div
class=
"tray-id-section"
>
<div
class=
"tray-display"
>
<div
class=
"tray-label"
>
当前托盘:
</div>
<div
class=
"tray-id"
>
{{
trayId
||
'TP-未绑定'
}}
</div>
</div>
<div
class=
"scan-section"
>
<input
type=
"text"
class=
"scan-input"
placeholder=
"扫描托盘条码..."
v-model=
"trayInput"
@
keyup
.
enter=
"setTrayId"
ref=
"trayInput"
>
<button
class=
"bind-btn"
@
click=
"setTrayId"
>
<i
class=
"fas fa-barcode"
></i>
绑定托盘
</button>
</div>
</div>
<!-- 设备矩阵区域 -->
<div
class=
"devices-grid-container"
>
<h2
class=
"grid-title"
><i
class=
"fas fa-microchip"
></i>
设备绑定矩阵 (8×9)
</h2>
<div
class=
"devices-grid"
>
<div
v-for=
"(device, index) in devices"
:key=
"index"
class=
"device-cell"
:class=
"
{
'active': activeCell === index,
'empty': !device.value
}"
@click="setActiveCell(index)"
>
<div
class=
"device-id"
>
{{
device
.
value
||
'+'
}}
</div>
<div
class=
"position-indicator"
>
{{
getPositionLabel
(
index
)
}}
</div>
</div>
</div>
</div>
<!-- 设备扫描区域 -->
<div
class=
"scan-section"
style=
"align-items: center;"
>
<input
type=
"text"
class=
"scan-input"
placeholder=
"扫描设备条码..."
v-model=
"deviceInput"
@
keyup
.
enter=
"addDevice"
ref=
"deviceInput"
>
<div
class=
"status-bar"
>
<i
class=
"fas fa-info-circle"
></i>
已绑定设备:
<span
class=
"filled-count"
>
{{
filledCount
}}
</span>
/72
</div>
</div>
<!-- 操作按钮区域 -->
<div
class=
"binding-controls"
>
<button
class=
"reset-btn"
@
click=
"resetAll"
>
<i
class=
"fas fa-redo"
></i>
重置所有
</button>
<button
class=
"bind-btn"
@
click=
"bindTray"
:disabled=
"filledCount === 0 || !trayId"
>
<i
class=
"fas fa-paper-plane"
></i>
提交绑定
</button>
</div>
<!-- 使用说明区域 -->
<div
class=
"instructions"
>
<h3><i
class=
"fas fa-lightbulb"
></i>
使用说明
</h3>
<ul>
<li>
1. 首先扫描
<span
class=
"highlight"
>
托盘条码
</span>
并点击绑定托盘按钮
</li>
<li>
2. 点击矩阵中的单元格或按顺序扫描
<span
class=
"highlight"
>
设备条码
</span>
(扫描枪自动识别)
</li>
<li>
3. 设备条码会自动填充到当前激活的单元格中
</li>
<li>
4. 可以手动点击任何单元格进行修改或重新扫描
</li>
<li>
5. 完成所有设备绑定后,点击
<span
class=
"highlight"
>
提交绑定
</span>
按钮
</li>
<li><i
class=
"fas fa-bolt scanner-icon"
></i>
提示:使用扫描枪时,请确保输入框获得焦点
</li>
</ul>
</div>
</div>
</
template
>
<
script
>
import
{
queryByDepartmentId
}
from
"@/api/storey/storey"
;
export
default
{
name
:
"TrayBinding"
,
data
()
{
return
{
// 托盘ID
trayId
:
''
,
trayInput
:
''
,
// 设备矩阵数据 (8x9 = 72个设备)
devices
:
Array
(
72
).
fill
().
map
((
_
,
i
)
=>
({
id
:
i
+
1
,
value
:
''
,
row
:
Math
.
floor
(
i
/
9
)
+
1
,
col
:
(
i
%
9
)
+
1
})),
// 当前激活的单元格
activeCell
:
0
,
// 设备输入
deviceInput
:
''
};
},
computed
:
{
// 计算已填充的设备数量
filledCount
()
{
return
this
.
devices
.
filter
(
d
=>
d
.
value
).
length
;
}
},
methods
:
{
// 设置托盘ID
setTrayId
()
{
if
(
this
.
trayInput
)
{
this
.
trayId
=
`TP-
${
this
.
trayInput
}
`
;
this
.
trayInput
=
''
;
this
.
$nextTick
(()
=>
{
this
.
$refs
.
deviceInput
.
focus
();
});
}
},
// 设置当前激活的单元格
setActiveCell
(
index
)
{
this
.
activeCell
=
index
;
this
.
$nextTick
(()
=>
{
this
.
$refs
.
deviceInput
.
focus
();
});
},
// 添加设备到当前激活单元格
addDevice
()
{
if
(
this
.
deviceInput
)
{
this
.
devices
[
this
.
activeCell
].
value
=
this
.
deviceInput
;
this
.
deviceInput
=
''
;
// 自动移动到下一个单元格
if
(
this
.
activeCell
<
71
)
{
this
.
activeCell
++
;
}
else
{
// 如果已经是最后一个,则回到第一个
this
.
activeCell
=
0
;
}
}
},
// 获取位置标签 (行-列)
getPositionLabel
(
index
)
{
const
row
=
Math
.
floor
(
index
/
9
)
+
1
;
const
col
=
(
index
%
9
)
+
1
;
return
`
${
row
}
-
${
col
}
`
;
},
// 绑定托盘
bindTray
()
{
const
boundDevices
=
this
.
devices
.
filter
(
d
=>
d
.
value
)
.
map
(
d
=>
({
position
:
this
.
getPositionLabel
(
d
.
id
-
1
),
deviceId
:
d
.
value
}));
alert
(
`托盘
${
this
.
trayId
}
绑定成功!\n绑定设备数量:
${
boundDevices
.
length
}
`
);
console
.
log
(
'托盘ID:'
,
this
.
trayId
);
console
.
log
(
'绑定设备:'
,
boundDevices
);
},
// 重置所有数据
resetAll
()
{
if
(
confirm
(
'确定要重置所有数据吗?'
))
{
this
.
trayId
=
''
;
this
.
trayInput
=
''
;
this
.
deviceInput
=
''
;
this
.
devices
=
this
.
devices
.
map
(
d
=>
({
...
d
,
value
:
''
}));
this
.
activeCell
=
0
;
this
.
$nextTick
(()
=>
{
this
.
$refs
.
trayInput
.
focus
();
});
}
}
},
mounted
()
{
// 初始化时聚焦到托盘输入框
this
.
$nextTick
(()
=>
{
this
.
$refs
.
trayInput
.
focus
();
});
}
};
</
script
>
<
style
scoped
>
*
{
margin
:
0
;
padding
:
0
;
box-sizing
:
border-box
;
font-family
:
'Segoe UI'
,
Tahoma
,
Geneva
,
Verdana
,
sans-serif
;
}
body
{
background
:
linear-gradient
(
135deg
,
#1a2a6c
,
#2c3e50
);
min-height
:
100vh
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
padding
:
20px
;
color
:
#fff
;
}
.tray-binding-container
{
width
:
100%
;
max-width
:
1200px
;
background
:
rgba
(
10
,
20
,
40
,
0.85
);
border-radius
:
20px
;
box-shadow
:
0
15px
35px
rgba
(
0
,
0
,
0
,
0.5
);
overflow
:
hidden
;
border
:
1px
solid
rgba
(
100
,
180
,
255
,
0.3
);
padding
:
30px
;
position
:
relative
;
}
.header
{
text-align
:
center
;
margin-bottom
:
30px
;
position
:
relative
;
}
.header
h1
{
font-size
:
2.8rem
;
background
:
linear-gradient
(
to
right
,
#4facfe
,
#00f2fe
);
-webkit-background-clip
:
text
;
color
:
transparent
;
margin-bottom
:
15px
;
text-shadow
:
0
0
15px
rgba
(
79
,
172
,
254
,
0.5
);
}
.header
p
{
color
:
#a0d2ff
;
font-size
:
1.2rem
;
max-width
:
700px
;
margin
:
0
auto
;
line-height
:
1.6
;
}
.tray-id-section
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
gap
:
20px
;
margin-bottom
:
40px
;
flex-wrap
:
wrap
;
}
.tray-display
{
background
:
rgba
(
0
,
40
,
80
,
0.4
);
border
:
2px
solid
rgba
(
64
,
158
,
255
,
0.6
);
border-radius
:
15px
;
padding
:
25px
40px
;
display
:
flex
;
align-items
:
center
;
gap
:
20px
;
box-shadow
:
0
5px
15px
rgba
(
0
,
0
,
0
,
0.3
);
}
.tray-label
{
font-size
:
1.4rem
;
color
:
#64c8ff
;
font-weight
:
bold
;
}
.tray-id
{
font-size
:
2.2rem
;
font-weight
:
bold
;
letter-spacing
:
3px
;
background
:
linear-gradient
(
to
right
,
#64c8ff
,
#3a7bd5
);
-webkit-background-clip
:
text
;
color
:
transparent
;
min-width
:
250px
;
text-align
:
center
;
}
.scan-section
{
display
:
flex
;
flex-direction
:
column
;
gap
:
15px
;
}
.scan-input
{
background
:
rgba
(
0
,
30
,
60
,
0.5
);
border
:
2px
solid
#409EFF
;
border-radius
:
50px
;
padding
:
15px
25px
;
color
:
white
;
font-size
:
1.2rem
;
width
:
300px
;
transition
:
all
0.3s
;
}
.scan-input
:focus
{
outline
:
none
;
border-color
:
#64c8ff
;
box-shadow
:
0
0
15px
rgba
(
100
,
200
,
255
,
0.5
);
}
.devices-grid-container
{
margin-bottom
:
40px
;
}
.grid-title
{
text-align
:
center
;
font-size
:
1.8rem
;
color
:
#64ffda
;
margin-bottom
:
25px
;
text-shadow
:
0
0
10px
rgba
(
100
,
255
,
218
,
0.3
);
}
.devices-grid
{
display
:
grid
;
grid-template-columns
:
repeat
(
9
,
1
fr
);
gap
:
12px
;
margin
:
0
auto
;
max-width
:
900px
;
}
.device-cell
{
background
:
rgba
(
30
,
60
,
100
,
0.4
);
border
:
2px
solid
rgba
(
64
,
158
,
255
,
0.5
);
border-radius
:
8px
;
aspect-ratio
:
1
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
cursor
:
pointer
;
transition
:
all
0.3s
;
position
:
relative
;
overflow
:
hidden
;
}
.device-cell
:hover
{
transform
:
translateY
(
-5px
);
box-shadow
:
0
8px
15px
rgba
(
0
,
0
,
0
,
0.3
);
border-color
:
#64c8ff
;
background
:
rgba
(
40
,
80
,
140
,
0.5
);
}
.device-cell.active
{
border-color
:
#64ffda
;
background
:
rgba
(
100
,
255
,
218
,
0.15
);
box-shadow
:
0
0
15px
rgba
(
100
,
255
,
218
,
0.4
);
}
.device-id
{
font-size
:
1.1rem
;
font-weight
:
bold
;
color
:
#fff
;
text-align
:
center
;
word-break
:
break-all
;
padding
:
5px
;
}
.device-cell.empty
.device-id
{
color
:
#a0d2ff
;
font-size
:
1.8rem
;
opacity
:
0.7
;
}
.position-indicator
{
position
:
absolute
;
bottom
:
5px
;
right
:
5px
;
font-size
:
0.7rem
;
color
:
rgba
(
255
,
255
,
255
,
0.6
);
}
.binding-controls
{
display
:
flex
;
justify-content
:
center
;
gap
:
30px
;
margin-top
:
40px
;
}
.bind-btn
{
background
:
linear-gradient
(
to
right
,
#11998e
,
#38ef7d
);
color
:
white
;
border
:
none
;
padding
:
18px
45px
;
font-size
:
1.4rem
;
font-weight
:
bold
;
border-radius
:
50px
;
cursor
:
pointer
;
display
:
flex
;
align-items
:
center
;
gap
:
15px
;
transition
:
all
0.3s
;
box-shadow
:
0
5px
15px
rgba
(
0
,
0
,
0
,
0.3
);
}
.bind-btn
:hover
{
transform
:
translateY
(
-5px
);
box-shadow
:
0
8px
20px
rgba
(
17
,
153
,
142
,
0.5
);
}
.bind-btn
:disabled
{
background
:
linear-gradient
(
to
right
,
#555
,
#777
);
cursor
:
not-allowed
;
transform
:
none
;
box-shadow
:
none
;
}
.reset-btn
{
background
:
linear-gradient
(
to
right
,
#ff416c
,
#ff4b2b
);
color
:
white
;
border
:
none
;
padding
:
18px
45px
;
font-size
:
1.4rem
;
font-weight
:
bold
;
border-radius
:
50px
;
cursor
:
pointer
;
display
:
flex
;
align-items
:
center
;
gap
:
15px
;
transition
:
all
0.3s
;
box-shadow
:
0
5px
15px
rgba
(
0
,
0
,
0
,
0.3
);
}
.reset-btn
:hover
{
transform
:
translateY
(
-5px
);
box-shadow
:
0
8px
20px
rgba
(
255
,
65
,
108
,
0.5
);
}
.status-bar
{
text-align
:
center
;
margin-top
:
30px
;
padding
:
15px
;
background
:
rgba
(
0
,
30
,
60
,
0.5
);
border-radius
:
10px
;
font-size
:
1.2rem
;
color
:
#64ffda
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
gap
:
15px
;
}
.filled-count
{
font-weight
:
bold
;
color
:
#64c8ff
;
font-size
:
1.4rem
;
}
.instructions
{
background
:
rgba
(
0
,
30
,
60
,
0.4
);
border-radius
:
15px
;
padding
:
25px
;
margin-top
:
40px
;
border
:
1px
solid
rgba
(
100
,
200
,
255
,
0.3
);
}
.instructions
h3
{
color
:
#64ffda
;
margin-bottom
:
15px
;
font-size
:
1.5rem
;
}
.instructions
ul
{
padding-left
:
25px
;
}
.instructions
li
{
margin-bottom
:
10px
;
line-height
:
1.6
;
color
:
#a0d2ff
;
}
.scanner-icon
{
color
:
#64ffda
;
animation
:
pulse
2s
infinite
;
}
@keyframes
pulse
{
0
%
{
opacity
:
0.6
;
}
50
%
{
opacity
:
1
;
}
100
%
{
opacity
:
0.6
;
}
}
.highlight
{
background
:
rgba
(
100
,
255
,
218
,
0.2
);
padding
:
2px
5px
;
border-radius
:
4px
;
}
/* 响应式设计 */
@media
(
max-width
:
900px
)
{
.devices-grid
{
grid-template-columns
:
repeat
(
6
,
1
fr
);
max-width
:
600px
;
}
.tray-id-section
{
flex-direction
:
column
;
}
}
@media
(
max-width
:
600px
)
{
.devices-grid
{
grid-template-columns
:
repeat
(
4
,
1
fr
);
max-width
:
400px
;
}
.tray-display
{
padding
:
15px
25px
;
}
.tray-id
{
font-size
:
1.8rem
;
min-width
:
200px
;
}
.bind-btn
,
.reset-btn
{
padding
:
15px
30px
;
font-size
:
1.2rem
;
}
}
</
style
>
zhmes-agecal-web/src/views/screen/index.vue
View file @
f8da175f
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
<!-- 顶部导航栏 -->
<!-- 顶部导航栏 -->
<div
class=
"header"
>
<div
class=
"header"
>
<div
class=
"system-title-wrapper"
>
<div
class=
"system-title-wrapper"
>
<div
class=
"system-title"
>
监控数字化视频管
控平台
</div>
<div
class=
"system-title"
>
泽宏老化监
控平台
</div>
<div
class=
"title-line"
></div>
<!-- 标题下的横线 -->
<div
class=
"title-line"
></div>
<!-- 标题下的横线 -->
</div>
</div>
...
@@ -23,7 +23,7 @@
...
@@ -23,7 +23,7 @@
<span
class=
"icon"
>
{{
item
.
icon
}}
</span>
<span
class=
"icon"
>
{{
item
.
icon
}}
</span>
<span
class=
"text"
>
{{
item
.
text
}}
</span>
<span
class=
"text"
>
{{
item
.
text
}}
</span>
<!-- 选中时显示的底部线条 -->
<!-- 选中时显示的底部线条 -->
<div
v-if=
"
selectedMenu
=== index"
class=
"active-line"
></div>
<div
v-if=
"
(selectedMenu === 3 ? 0 : selectedMenu)
=== index"
class=
"active-line"
></div>
</div>
</div>
</div>
</div>
...
@@ -37,7 +37,15 @@
...
@@ -37,7 +37,15 @@
<div
class=
"content-area"
>
<div
class=
"content-area"
>
<div
class=
"scroll-container"
>
<div
class=
"scroll-container"
>
<transition
name=
"fade"
mode=
"out-in"
>
<transition
name=
"fade"
mode=
"out-in"
>
<component
:is=
"currentComponent"
/>
<!--
<component
:is=
"currentComponent"
/>
-->
<!-- 在动态组件中传递参数 -->
<!-- 添加返回事件处理 -->
<component
:is=
"currentComponent"
:modbusDeviceData=
"modbusDeviceData"
@
cabinet-click=
"handleCabinetClick"
@
go-back=
"handleGoBack"
/>
</transition>
</transition>
</div>
</div>
</div>
</div>
...
@@ -49,29 +57,50 @@
...
@@ -49,29 +57,50 @@
import
AgingCabinetBoard
from
'./components/AgingCabinetBoard.vue'
import
AgingCabinetBoard
from
'./components/AgingCabinetBoard.vue'
import
AgingLayer
from
'./components/AgingLayer'
import
AgingLayer
from
'./components/AgingLayer'
import
RealTimeData
from
'./components/RealTimeData'
import
RealTimeData
from
'./components/RealTimeData'
import
TrayBinding
from
"@/views/screen/components/TrayBinding"
;
export
default
{
export
default
{
components
:
{
components
:
{
AgingCabinetBoard
,
AgingCabinetBoard
,
AgingLayer
,
AgingLayer
,
RealTimeData
RealTimeData
,
TrayBinding
},
},
data
()
{
data
()
{
return
{
return
{
selectedMenu
:
0
,
// 默认选中第一个
selectedMenu
:
0
,
// 默认选中第一个
menuItems
:
[
menuItems
:
[
{
icon
:
'📷'
,
text
:
'老化柜看板'
,
component
:
'AgingCabinetBoard'
},
{
icon
:
'📷'
,
text
:
'老化柜看板'
,
component
:
'AgingCabinetBoard'
},
{
icon
:
'📊'
,
text
:
'
老化层看板'
,
component
:
'AgingLayer
'
},
{
icon
:
'📊'
,
text
:
'
托盘绑定'
,
component
:
'TrayBinding
'
},
{
icon
:
'📦'
,
text
:
'实时数据'
,
component
:
'RealTimeData'
}
{
icon
:
'📦'
,
text
:
'实时数据'
,
component
:
'RealTimeData'
}
,
],
],
selectMenuItems
:
[
{
icon
:
'📷'
,
text
:
'老化柜看板'
,
component
:
'AgingCabinetBoard'
},
{
icon
:
'📊'
,
text
:
'托盘绑定'
,
component
:
'TrayBinding'
},
{
icon
:
'📦'
,
text
:
'实时数据'
,
component
:
'RealTimeData'
},
{
icon
:
'🔍'
,
text
:
'老化层详情'
,
component
:
'AgingLayer'
}
// 新增菜单项
],
modbusDeviceData
:
null
// 存储传递的柜子ID
}
}
},
},
computed
:
{
computed
:
{
currentComponent
()
{
currentComponent
()
{
return
this
.
m
enuItems
[
this
.
selectedMenu
].
component
;
return
this
.
selectM
enuItems
[
this
.
selectedMenu
].
component
;
},
},
},
},
methods
:
{
methods
:
{
// 处理返回事件
handleGoBack
()
{
// 返回老化柜看板(菜单索引 0)
this
.
selectedMenu
=
0
;
this
.
modbusDeviceData
=
null
;
},
// 接收从 AgingCabinetBoard 传递的柜子ID
handleCabinetClick
(
modbusDeviceData
)
{
this
.
modbusDeviceData
=
modbusDeviceData
;
// 切换到 AgingLayer 组件(对应菜单索引 3)
this
.
selectedMenu
=
3
;
},
selectMenu
(
index
)
{
selectMenu
(
index
)
{
// if(index === 3) {
// if(index === 3) {
// this.goToAdmin();
// this.goToAdmin();
...
@@ -87,10 +116,6 @@ export default {
...
@@ -87,10 +116,6 @@ export default {
goToAdmin
()
{
goToAdmin
()
{
this
.
$router
.
push
(
'/index'
)
// 或者 '/dashboard' 如果已经登录
this
.
$router
.
push
(
'/index'
)
// 或者 '/dashboard' 如果已经登录
},
},
handleMenuSelect
(
index
)
{
// 可以在这里根据 index 做更多操作,比如加载数据等
this
.
activeMenu
=
index
;
}
}
}
}
}
</
script
>
</
script
>
...
@@ -152,6 +177,18 @@ export default {
...
@@ -152,6 +177,18 @@ export default {
margin-top
:
10px
;
margin-top
:
10px
;
}
}
/* 选中时的底部线条 */
.active-line
{
position
:
absolute
;
bottom
:
-6px
;
/* 略微低于盒子 */
left
:
0
;
right
:
0
;
height
:
2px
;
background
:
linear-gradient
(
to
right
,
transparent
,
#409EFF
,
transparent
);
animation
:
lineGrow
0.3s
forwards
;
}
/* 菜单组 */
/* 菜单组 */
.menu-group
{
.menu-group
{
display
:
flex
;
display
:
flex
;
...
@@ -166,7 +203,8 @@ export default {
...
@@ -166,7 +203,8 @@ export default {
gap
:
8px
;
gap
:
8px
;
padding
:
10px
20px
;
padding
:
10px
20px
;
position
:
relative
;
position
:
relative
;
transform
:
rotate
(
-2deg
);
/* 整体倾斜一点,模拟菱形外观 */
/* 整体倾斜一点,模拟菱形外观 */
transform
:
rotate
(
0deg
);
font-family
:
Arial
,
sans-serif
;
font-family
:
Arial
,
sans-serif
;
color
:
white
;
color
:
white
;
z-index
:
1
;
z-index
:
1
;
...
@@ -175,7 +213,7 @@ export default {
...
@@ -175,7 +213,7 @@ export default {
}
}
.diamond-box
:hover
{
.diamond-box
:hover
{
transform
:
rotate
(
-2
deg
)
scale
(
1.05
);
transform
:
rotate
(
0
deg
)
scale
(
1.05
);
}
}
.diamond-box
::before
{
.diamond-box
::before
{
...
@@ -186,7 +224,7 @@ export default {
...
@@ -186,7 +224,7 @@ export default {
right
:
0
;
right
:
0
;
bottom
:
0
;
bottom
:
0
;
border
:
1px
solid
#409EFF
;
border
:
1px
solid
#409EFF
;
transform
:
rotate
(
2
deg
);
transform
:
rotate
(
0
deg
);
box-sizing
:
border-box
;
box-sizing
:
border-box
;
z-index
:
-1
;
z-index
:
-1
;
background-color
:
rgba
(
64
,
158
,
255
,
0.1
);
background-color
:
rgba
(
64
,
158
,
255
,
0.1
);
...
@@ -226,19 +264,9 @@ export default {
...
@@ -226,19 +264,9 @@ export default {
/* 动画效果 */
/* 动画效果 */
@keyframes
lineMove
{
@keyframes
lineMove
{
0
%
{
transform
:
scaleX
(
1
);
}
0
%
{
transform
:
scaleX
(
1
);
}
100
%
{
transform
:
scaleX
(
0.9
);
}
100
%
{
transform
:
scaleX
(
1
);
}
}
}
/* 选中时的底部线条 */
.active-line
{
position
:
absolute
;
bottom
:
-6px
;
/* 略微低于盒子 */
left
:
0
;
right
:
0
;
height
:
2px
;
background
:
linear-gradient
(
to
right
,
transparent
,
#409EFF
,
transparent
);
animation
:
lineGrow
0.3s
forwards
;
}
/* 动画:从中间向两边展开 */
/* 动画:从中间向两边展开 */
@keyframes
lineGrow
{
@keyframes
lineGrow
{
...
@@ -275,7 +303,7 @@ export default {
...
@@ -275,7 +303,7 @@ export default {
@keyframes
fadeIn
{
@keyframes
fadeIn
{
from
{
from
{
opacity
:
0
;
opacity
:
0
;
transform
:
translateY
(
10px
);
transform
:
translateY
(
0
);
}
}
to
{
to
{
opacity
:
1
;
opacity
:
1
;
...
...
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