Commit f8da175f authored by wanghao's avatar wanghao

1 托盘和 设备 数据绑定界面开发中

parent 2b92be96
......@@ -55,6 +55,15 @@ public class TStoreyInfoController extends BaseController
return util.exportExcel(list, "老化层信息数据");
}
/**
* 获取老化层信息详细信息
*/
@GetMapping(value = "/queryByDepartmentId/{fEquipmentId}")
public AjaxResult queryByDepartmentId(@PathVariable("fEquipmentId") Long fEquipmentId)
{
return AjaxResult.success(tStoreyInfoService.queryByDepartmentId(fEquipmentId));
}
/**
* 获取老化层信息详细信息
*/
......
......@@ -7,12 +7,16 @@ import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.zehong.framework.modbus4j.Modbus4jUtils;
import com.zehong.system.domain.TEquipmentAlarmData;
import com.zehong.system.domain.TEquipmentInfo;
import com.zehong.system.domain.TStoreyInfo;
import com.zehong.system.domain.modbus.ModbusDeviceData;
import com.zehong.system.service.ITEquipmentAlarmDataService;
import com.zehong.system.service.ITEquipmentInfoService;
import com.zehong.system.service.ITStoreyInfoService;
import com.zehong.web.task.AgingCabinetInspectionAndPowerCheckTask;
import com.zehong.web.task.PowerOffCommandEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
......@@ -42,6 +46,9 @@ public class TestTaskController {
@Resource
private ITEquipmentAlarmDataService tEquipmentAlarmDataService;
@Resource
private ApplicationEventPublisher eventPublisher; // 新增事件发布器
/**
* 五分钟一次
* 1.老化柜、标定柜巡查
......@@ -80,16 +87,14 @@ public class TestTaskController {
}
List<CompletableFuture<ModbusDeviceData>> futures = equipmentInfos.stream().map(equipmentInfo -> CompletableFuture.supplyAsync(() -> {
ModbusMaster master = null;
// 构造结果对象
ModbusDeviceData deviceData;
// 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);
// 返回结果
return createErrorData(equipmentInfo,"","",integerObjectMap);
// 返回结果 无错误
return createErrorData(equipmentInfo, "", "", integerObjectMap);
} catch (ModbusInitException e) {
// 记录异常数据
......@@ -104,16 +109,16 @@ public class TestTaskController {
// 返回错误信息
Map<Integer, Object> errorMap = new HashMap<>();
// 返回结果
return createErrorData(equipmentInfo,"2","Modbus初始化失败",errorMap);
return createErrorData(equipmentInfo, "2", "Modbus初始化失败", errorMap);
// 层有错误返回 柜可能连不上也在这个报错里面
} 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.setfEquipmentCode(equipmentInfo.getfEquipmentCode());
alarmData.setfAlarmData("定时任务巡检:老化柜网线没插好");
// 线接错误
// 线接错误
} else {
// 记录异常数据
alarmData.setfAlarmType("01"); //01.老化柜 02.机械臂 03.老化层 04.点位
......@@ -128,17 +133,17 @@ public class TestTaskController {
Map<Integer, Object> errorMap = new HashMap<>();
// 网线没插好通讯不上
// 返回结果
if(e.getMessage().equals("java.net.SocketTimeoutException: connect timed out")) {
return createErrorData(equipmentInfo,"2","网线没插好",errorMap);
if (e.getMessage().equals("java.net.SocketTimeoutException: connect timed out")) {
return createErrorData(equipmentInfo, "2", "定时任务巡检:网线没插好", errorMap);
} else {
// 线接错误
// 返回结果
return createErrorData(equipmentInfo,"2","通信线路没接好",errorMap);
return createErrorData(equipmentInfo, "2", "定时任务巡检:通信线路没接好", errorMap);
}
} catch (ErrorResponseException e) {
Map<Integer, Object> errorMap = new HashMap<>();
// 返回结果
return createErrorData(equipmentInfo,"2","ErrorResponseException",errorMap);
return createErrorData(equipmentInfo, "2", "定时任务巡检:ErrorResponseException", errorMap);
} finally {
if (master != null) {
master.destroy();
......@@ -168,15 +173,16 @@ public class TestTaskController {
return deferredResult;
}
private ModbusDeviceData createErrorData(TEquipmentInfo equipmentInfo,String status,
String errorReason,Map<Integer, Object> integerObjectMap) {
private ModbusDeviceData createErrorData(TEquipmentInfo equipmentInfo, String status,
String errorReason, Map<Integer, Object> integerObjectMap) {
ModbusDeviceData deviceData = new ModbusDeviceData();
deviceData.setId(equipmentInfo.getfEquipmentId());
deviceData.setfIp(equipmentInfo.getfIp());
deviceData.setfPort(equipmentInfo.getfPort());
deviceData.setDeviceCode(equipmentInfo.getfEquipmentCode());
deviceData.setDeviceStatus(status);
deviceData.setErrorReason(errorReason);
if(integerObjectMap != null){
if (integerObjectMap != null) {
deviceData.setRegisterValues(integerObjectMap.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
......@@ -188,28 +194,34 @@ public class TestTaskController {
// 处理 老化柜 是 运行 开始 空闲
private List<ModbusDeviceData> processDeviceData(List<ModbusDeviceData> deviceDataList) {
for (ModbusDeviceData modbusDeviceData : deviceDataList) {
Map<Integer, String> registerValues = modbusDeviceData.getRegisterValues();
boolean isRun = false;
for (Map.Entry<Integer, String> entry : registerValues.entrySet()) {
Integer registerOffset = entry.getKey();
String registerValue = entry.getValue();
if ("true".equals(registerValue)) {
isRun = true;
// 要给这个 层 发断电的 指令
} else {
try {
ModbusMaster master = Modbus4jUtils.getMaster(modbusDeviceData.getfIp(), modbusDeviceData.getfPort());
Modbus4jUtils.writeCoil(master, 1, registerOffset, false);
} catch (ModbusInitException | ModbusTransportException e) {
throw new RuntimeException(e);
// 大于0 说明 柜能通信;小于0 说明柜 不能通信
if(registerValues.size() > 0) {
boolean isRun = false;
for (Map.Entry<Integer, String> entry : registerValues.entrySet()) {
Integer registerOffset = entry.getKey();
String registerValue = entry.getValue();
if ("true".equals(registerValue)) {
isRun = true;
// 要给这个 层 发断电的 指令
} else {
// 发布断电指令事件(不再直接执行)
eventPublisher.publishEvent(new PowerOffCommandEvent(
this,
modbusDeviceData.getDeviceCode(),
modbusDeviceData.getfIp(),
modbusDeviceData.getfPort(),
registerOffset
));
}
}
}
if(isRun) {
modbusDeviceData.setDeviceStatus("1");
} else {
modbusDeviceData.setDeviceStatus("0");
if (isRun) {
modbusDeviceData.setDeviceStatus("1");
} else {
modbusDeviceData.setDeviceStatus("0");
}
}
}
return deviceDataList;
......
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);
}
}
}
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; }
}
package com.zehong.system.domain;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
......@@ -17,6 +20,14 @@ public class TStoreyInfo extends BaseEntity
{
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 */
private Long fStoreyId;
......@@ -40,6 +51,8 @@ public class TStoreyInfo extends BaseEntity
@Excel(name = "状态:0空闲,1运行,2故障,3断电")
private String fStatus;
private String statusStr;
/** 老化开始时间 */
@JsonFormat(pattern = "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
{
return fStatus;
}
public String getStatusStr() {
return statusStrMap.get(fStatus);
}
public void setStatusStr(String statusStr) {
this.statusStr = statusStr;
}
public void setfPort(Integer fPort)
{
this.fPort = fPort;
......
......@@ -8,6 +8,10 @@ import java.util.Map;
* @description modbus设备数据
*/
public class ModbusDeviceData {
// equipmentId
private Long id;
private String deviceCode;
/** IP地址 */
......@@ -75,4 +79,12 @@ public class ModbusDeviceData {
public void setfPort(Integer fPort) {
this.fPort = fPort;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
......@@ -35,6 +35,8 @@ public interface TStoreyInfoMapper
*/
public List<TStoreyInfo> selectTStoreyInfoList(TStoreyInfo tStoreyInfo);
public List<TStoreyInfo> queryByDepartmentId(Long fEquipmentId);
/**
* 新增老化层信息
*
......
......@@ -35,6 +35,8 @@ public interface ITStoreyInfoService
*/
public List<TStoreyInfo> selectTStoreyInfoList(TStoreyInfo tStoreyInfo);
public List<TStoreyInfo> queryByDepartmentId(Long fDepartmentId);
/**
* 新增老化层信息
*
......
......@@ -55,6 +55,16 @@ public class TStoreyInfoServiceImpl implements ITStoreyInfoService
return tStoreyInfoMapper.selectTStoreyInfoList(tStoreyInfo);
}
/**
* 根据设备id 查询层信息
* @param fEquipmentId f
* @return r
*/
@Override
public List<TStoreyInfo> queryByDepartmentId(Long fEquipmentId) {
return tStoreyInfoMapper.queryByDepartmentId(fEquipmentId);
}
/**
* 新增老化层信息
*
......
......@@ -18,7 +18,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<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>
<select id="selectTStoreyInfoList" parameterType="TStoreyInfo" resultMap="TStoreyInfoResult">
......@@ -34,6 +34,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="fAlarmTime != null "> and f_alarm_time = #{fAlarmTime}</if>
</where>
</select>
<select id="queryByDepartmentId" parameterType="long" resultMap="TStoreyInfoResult">
<include refid="selectTStoreyInfoVo"/>
where f_equipment_id = #{fEquipmentId}
</select>
<select id="selectTStoreyInfoById" parameterType="Long" resultMap="TStoreyInfoResult">
<include refid="selectTStoreyInfoVo"/>
......
......@@ -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) {
return request({
......
......@@ -29,7 +29,7 @@
placement="top"
>
<el-card
:class="statusMap[item.status]"
:class="statusMap[item.deviceStatus]"
style="
width: 150px;
height: 150px;
......@@ -59,49 +59,13 @@ export default {
return {
// 示例数据格式,实际从后端获取
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个
],
// 状态对应的颜色类名
statusMap: {
default: 'default',
available: 'available',
occupied: 'occupied'
0: 'default',
1: 'available',
2: 'occupied'
},
agingCabinetList: null
};
......@@ -118,27 +82,27 @@ export default {
}
},
mounted() {
//this.testAgingCabinetAndPowerCheck();
this.testAgingCabinetAndPowerCheck();
},
methods: {
handleCardClick(item) {
this.msgSuccess("你想看层信息是吧");
// 触发事件传递 cabinetId 给父组件
this.$emit('cabinet-click', item);
},
getTooltipContent(item) {
switch (item.status) {
case 'occupied':
return item.faultReason || '无故障详情';
case 'available':
switch (item.deviceStatus) {
case '2':
return item.errorReason || '无故障详情';
case '1':
return '运行中';
case 'default':
case '0':
default:
return '空闲';
}
},
testAgingCabinetAndPowerCheck() {
getAgingCabinetAndPowerCheck().then(response => {
this.agingCabinetList = response;
this.cabinets = response;
}
);
}
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
<!-- 顶部导航栏 -->
<div class="header">
<div class="system-title-wrapper">
<div class="system-title">监控数字化视频管控平台</div>
<div class="system-title">泽宏老化监控平台</div>
<div class="title-line"></div> <!-- 标题下的横线 -->
</div>
......@@ -23,7 +23,7 @@
<span class="icon">{{ item.icon }}</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>
......@@ -37,7 +37,15 @@
<div class="content-area">
<div class="scroll-container">
<transition name="fade" mode="out-in">
<component :is="currentComponent" />
<!-- <component :is="currentComponent" />-->
<!-- 在动态组件中传递参数 -->
<!-- 添加返回事件处理 -->
<component
:is="currentComponent"
:modbusDeviceData="modbusDeviceData"
@cabinet-click="handleCabinetClick"
@go-back="handleGoBack"
/>
</transition>
</div>
</div>
......@@ -49,29 +57,50 @@
import AgingCabinetBoard from './components/AgingCabinetBoard.vue'
import AgingLayer from './components/AgingLayer'
import RealTimeData from './components/RealTimeData'
import TrayBinding from "@/views/screen/components/TrayBinding";
export default {
components: {
AgingCabinetBoard,
AgingLayer,
RealTimeData
RealTimeData,
TrayBinding
},
data() {
return {
selectedMenu: 0, // 默认选中第一个
menuItems: [
{ icon: '📷', text: '老化柜看板', component: 'AgingCabinetBoard' },
{ icon: '📊', text: '老化层看板', component: 'AgingLayer' },
{ icon: '📦', text: '实时数据', component: 'RealTimeData' }
{ icon: '📊', text: '托盘绑定', component: 'TrayBinding' },
{ 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: {
currentComponent() {
return this.menuItems[this.selectedMenu].component;
return this.selectMenuItems[this.selectedMenu].component;
},
},
methods: {
// 处理返回事件
handleGoBack() {
// 返回老化柜看板(菜单索引 0)
this.selectedMenu = 0;
this.modbusDeviceData = null;
},
// 接收从 AgingCabinetBoard 传递的柜子ID
handleCabinetClick(modbusDeviceData) {
this.modbusDeviceData = modbusDeviceData;
// 切换到 AgingLayer 组件(对应菜单索引 3)
this.selectedMenu = 3;
},
selectMenu(index) {
// if(index === 3) {
// this.goToAdmin();
......@@ -87,10 +116,6 @@ export default {
goToAdmin() {
this.$router.push('/index') // 或者 '/dashboard' 如果已经登录
},
handleMenuSelect(index) {
// 可以在这里根据 index 做更多操作,比如加载数据等
this.activeMenu = index;
}
}
}
</script>
......@@ -152,6 +177,18 @@ export default {
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 {
display: flex;
......@@ -166,7 +203,8 @@ export default {
gap: 8px;
padding: 10px 20px;
position: relative;
transform: rotate(-2deg); /* 整体倾斜一点,模拟菱形外观 */
/* 整体倾斜一点,模拟菱形外观 */
transform: rotate(0deg);
font-family: Arial, sans-serif;
color: white;
z-index: 1;
......@@ -175,7 +213,7 @@ export default {
}
.diamond-box:hover {
transform: rotate(-2deg) scale(1.05);
transform: rotate(0deg) scale(1.05);
}
.diamond-box::before {
......@@ -186,7 +224,7 @@ export default {
right: 0;
bottom: 0;
border: 1px solid #409EFF;
transform: rotate(2deg);
transform: rotate(0deg);
box-sizing: border-box;
z-index: -1;
background-color: rgba(64, 158, 255, 0.1);
......@@ -226,19 +264,9 @@ export default {
/* 动画效果 */
@keyframes lineMove {
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 {
......@@ -275,7 +303,7 @@ export default {
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
transform: translateY(0);
}
to {
opacity: 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment