# Conflicts:
#	ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/exceptionController/AlertMessageController.java
dev
lzh1232 8 months ago
commit e096d8e458
  1. 8
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/equManagement/EquBaseController.java
  2. 3
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/equManagement/ScheduleRulesController.java
  3. 13
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/exceptionController/AlertMessageController.java
  4. 10
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/exceptionController/AlertRuleController.java
  5. 2
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/exceptionController/equAssessment.java
  6. 2
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/message/messageController.java
  7. 26
      ALOps_sys_backend/alops-chat/src/main/java/com/alops/chat/service/AItokenService.java
  8. 2
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/AlertDto.java
  9. 211
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/AlertMessages.java
  10. 3
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/job/GatherJob.java
  11. 3
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/mapper/AlertMessageMapper.java
  12. 3
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/IAlertMessageService.java
  13. 3
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertMessageServiceImpl.java
  14. 6
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/EquBaseServiceImpl.java
  15. 87
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/ScheduleRulesServiceImpl.java
  16. 23
      ALOps_sys_backend/alops-system/src/main/resources/mapper/system/AlertMessageMapper.xml
  17. 2
      ALOps_sys_fe/alops-ui/.env.development
  18. 2
      ALOps_sys_fe/alops-ui/.env.production
  19. 2
      ALOps_sys_fe/alops-ui/package.json
  20. 3
      ALOps_sys_fe/alops-ui/public/index.html
  21. 2
      ALOps_sys_fe/alops-ui/src/layout/components/Sidebar/Logo.vue
  22. 2
      ALOps_sys_fe/alops-ui/src/utils/websocket.js
  23. 6
      ALOps_sys_fe/alops-ui/src/views/QandA/Aiassistant/index.vue
  24. 45
      ALOps_sys_fe/alops-ui/src/views/QandA/knowledge/index.vue
  25. 1
      ALOps_sys_fe/alops-ui/src/views/device/deviceInformation/index.vue
  26. 12
      ALOps_sys_fe/alops-ui/src/views/device/deviceManufacturer/index.vue
  27. 4
      ALOps_sys_fe/alops-ui/src/views/device/deviceType/index.vue
  28. 15
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/devicesState/cardItem.vue
  29. 778
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/devicesState/detail.vue
  30. 26
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/inMonitor/message/index.vue
  31. 6
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/inMonitor/rules/index.vue
  32. 6
      ALOps_sys_fe/alops-ui/src/views/index.vue
  33. 4
      ALOps_sys_fe/alops-ui/src/views/message/index.vue

@ -50,6 +50,7 @@ public class EquBaseController extends BaseController
@PreAuthorize("@ss.hasPermi('device:files:list')") @PreAuthorize("@ss.hasPermi('device:files:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询多个设备信息") @ApiOperation("查询多个设备信息")
@Log(title = "设备档案查询", businessType = BusinessType.OTHER)
public TableDataInfo list( EquBaseQueryDto equBase) public TableDataInfo list( EquBaseQueryDto equBase)
{ {
startPage(); startPage();
@ -152,6 +153,7 @@ public class EquBaseController extends BaseController
@PreAuthorize("@ss.hasPermi('device:files:query1')") @PreAuthorize("@ss.hasPermi('device:files:query1')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("查询单个设备信息") @ApiOperation("查询单个设备信息")
@Log(title = "单个设备查询", businessType = BusinessType.OTHER)
public AjaxResult getInfo(@PathVariable("id") String id) public AjaxResult getInfo(@PathVariable("id") String id)
{ {
return success(equBaseService.selectEquBaseById(id)); return success(equBaseService.selectEquBaseById(id));
@ -226,7 +228,7 @@ public class EquBaseController extends BaseController
* MultipartFile file * MultipartFile file
*/ */
@PreAuthorize("@ss.hasPermi('device:files:add')") @PreAuthorize("@ss.hasPermi('device:files:add')")
@Log(title = "设备基本信息", businessType = BusinessType.INSERT) @Log(title = "增加设备档案信息", businessType = BusinessType.INSERT)
@PostMapping(value = "/add") @PostMapping(value = "/add")
@ApiOperation("增加设备档案信息") @ApiOperation("增加设备档案信息")
public AjaxResult add(@RequestBody EquBase equBase) { public AjaxResult add(@RequestBody EquBase equBase) {
@ -249,7 +251,7 @@ public class EquBaseController extends BaseController
* 修改设备基本信息 * 修改设备基本信息
*/ */
@PreAuthorize("@ss.hasPermi('device:files:edit')") @PreAuthorize("@ss.hasPermi('device:files:edit')")
@Log(title = "设备基本信息", businessType = BusinessType.UPDATE) @Log(title = "更新设备档案基本信息", businessType = BusinessType.UPDATE)
@PutMapping("/modify") @PutMapping("/modify")
@ApiOperation("修改设备档案信息") @ApiOperation("修改设备档案信息")
public AjaxResult edit(@RequestBody EquBase equBase){ public AjaxResult edit(@RequestBody EquBase equBase){
@ -268,7 +270,7 @@ public class EquBaseController extends BaseController
* 删除设备基本信息 * 删除设备基本信息
*/ */
@PreAuthorize("@ss.hasPermi('device:files:remove')") @PreAuthorize("@ss.hasPermi('device:files:remove')")
@Log(title = "设备基本信息", businessType = BusinessType.DELETE) @Log(title = "删除设备档案基本信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}") @DeleteMapping("/{ids}")
@ApiOperation("删除设备档案信息") @ApiOperation("删除设备档案信息")
public AjaxResult remove(@PathVariable String[] ids) public AjaxResult remove(@PathVariable String[] ids)

@ -61,7 +61,7 @@ public class ScheduleRulesController extends BaseController
@PreAuthorize("@ss.hasPermi('device:deviceInformation:protoCollect')") @PreAuthorize("@ss.hasPermi('device:deviceInformation:protoCollect')")
@PostMapping("/addRule") @PostMapping("/addRule")
@ApiOperation("立即确定") @ApiOperation("立即确定")
@Log(title = "设备信息采集", businessType = BusinessType.OTHER)
public AjaxResult run(@RequestBody ScheduleRules newRule) throws SchedulerException, ExecutionException, InterruptedException { public AjaxResult run(@RequestBody ScheduleRules newRule) throws SchedulerException, ExecutionException, InterruptedException {
// 先检查是否有任务正在执行 // 先检查是否有任务正在执行
@ -99,6 +99,7 @@ public class ScheduleRulesController extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('equipment:rules:list')") @PreAuthorize("@ss.hasPermi('equipment:rules:list')")
@GetMapping("/list") @GetMapping("/list")
@Log(title = "设备信息采集基本信息", businessType = BusinessType.OTHER)
public TableDataInfo list(ScheduleRules scheduleRules) public TableDataInfo list(ScheduleRules scheduleRules)
{ {
startPage(); startPage();

@ -10,6 +10,7 @@ import com.alops.common.core.page.TableDataInfo;
import com.alops.common.enums.BusinessType; import com.alops.common.enums.BusinessType;
import com.alops.system.domain.AlertMessage; import com.alops.system.domain.AlertMessage;
import com.alops.system.domain.dto.AlertDto; import com.alops.system.domain.dto.AlertDto;
import com.alops.system.domain.vo.AlertMessages;
import com.alops.system.domain.vo.homeEquAlertMessageVo; import com.alops.system.domain.vo.homeEquAlertMessageVo;
import com.alops.system.service.IAlertLaunchService; import com.alops.system.service.IAlertLaunchService;
import com.alops.system.domain.dto.AlertStatisticDto; import com.alops.system.domain.dto.AlertStatisticDto;
@ -79,7 +80,7 @@ public class AlertMessageController extends BaseController
@PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:statistic:list')") @PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:statistic:list')")
@GetMapping ("/statistic/list") @GetMapping ("/statistic/list")
@ApiOperation("首页查询预警信息") @ApiOperation("首页查询预警信息")
@Log(title = "查询预警信息", businessType = BusinessType.SELECT) @Log(title = "查询预警信息", businessType = BusinessType.OTHER)
public TableDataInfo homeList() public TableDataInfo homeList()
{ {
startPage(); startPage();
@ -94,11 +95,11 @@ public class AlertMessageController extends BaseController
@PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:list')") @PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:list')")
@GetMapping ("/list") @GetMapping ("/list")
@ApiOperation("查询预警信息") @ApiOperation("查询预警信息")
@Log(title = "查询预警信息", businessType = BusinessType.UPDATE) @Log(title = "查询预警信息", businessType = BusinessType.OTHER)
public TableDataInfo list( AlertDto alertMessage) public TableDataInfo list( AlertDto alertMessage)
{ {
startPage(); startPage();
List<AlertMessage> list = alertMessageService.selectAlertMessageList(alertMessage); List<AlertMessages> list = alertMessageService.selectAlertMessageList(alertMessage);
return getDataTable(list); return getDataTable(list);
} }
@ -107,7 +108,6 @@ public class AlertMessageController extends BaseController
* 查询界面预警信息+++ * 查询界面预警信息+++
*/ */
@PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:listByEquId')") @PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:listByEquId')")
@Log(title = "界面预警信息", businessType = BusinessType.SELECT)
@GetMapping("/{equId}") @GetMapping("/{equId}")
@ApiOperation("获取界面ALlertMessage信息") @ApiOperation("获取界面ALlertMessage信息")
public TableDataInfo listByEquId(@PathVariable("equId")String equId) public TableDataInfo listByEquId(@PathVariable("equId")String equId)
@ -122,7 +122,6 @@ public class AlertMessageController extends BaseController
* 统计预警次数信息 * 统计预警次数信息
*/ */
@PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:statistic')") @PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:statistic')")
@Log(title = "界面预警信息", businessType = BusinessType.SELECT)
@GetMapping("/times") @GetMapping("/times")
@ApiOperation("统计预警次数信息") @ApiOperation("统计预警次数信息")
public AjaxResult getAlertStatistic() { public AjaxResult getAlertStatistic() {
@ -133,9 +132,9 @@ public class AlertMessageController extends BaseController
/** /**
* 删除预警信息 * 删除预警信息
*/ */
@PreAuthorize("@ss.hasPermi('system:message:remove')") @PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:remove')")
@ApiOperation("删除预警信息") @ApiOperation("删除预警信息")
@Log(title = "删除预警信息", businessType = BusinessType.UPDATE) @Log(title = "删除预警信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}") @DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) public AjaxResult remove(@PathVariable Long[] ids)
{ {

@ -50,7 +50,7 @@ public class AlertRuleController extends BaseController {
*/ */
@PreAuthorize("@ss.hasPermi('inMonitoring:alertRule:add')") @PreAuthorize("@ss.hasPermi('inMonitoring:alertRule:add')")
@ApiOperation("增加预警规则") @ApiOperation("增加预警规则")
@Log(title = "【增加预警规则】", businessType = BusinessType.DELETE) @Log(title = "【增加预警规则】", businessType = BusinessType.INSERT)
@PostMapping("/addRule") @PostMapping("/addRule")
public AjaxResult addRule(@RequestBody AlertRuleAddDto dto) { public AjaxResult addRule(@RequestBody AlertRuleAddDto dto) {
try { try {
@ -69,7 +69,7 @@ public class AlertRuleController extends BaseController {
*/ */
@PreAuthorize("@ss.hasPermi('inMonitoring:alertRule:edit')") @PreAuthorize("@ss.hasPermi('inMonitoring:alertRule:edit')")
@ApiOperation("修改预警规则") @ApiOperation("修改预警规则")
@Log(title = "【修改预警规则】", businessType = BusinessType.DELETE) @Log(title = "【修改预警规则】", businessType = BusinessType.UPDATE)
@PutMapping("/editRule") @PutMapping("/editRule")
public AjaxResult editRule(@RequestBody AlertRuleAddDto dto) { public AjaxResult editRule(@RequestBody AlertRuleAddDto dto) {
try { try {
@ -86,7 +86,7 @@ public class AlertRuleController extends BaseController {
*/ */
@PreAuthorize("@ss.hasPermi('inMonitoring:alertRule:list')") @PreAuthorize("@ss.hasPermi('inMonitoring:alertRule:list')")
@GetMapping("/list") @GetMapping("/list")
@Log(title = "【查询预警规则】", businessType = BusinessType.DELETE) @Log(title = "【查询预警规则】", businessType = BusinessType.OTHER)
@ApiOperation("查询预警规则") @ApiOperation("查询预警规则")
public TableDataInfo list(AlertRule alertRule) { public TableDataInfo list(AlertRule alertRule) {
startPage(); startPage();
@ -102,7 +102,7 @@ public class AlertRuleController extends BaseController {
@PreAuthorize("@ss.hasPermi('inMonitoring:alertRule:query')") @PreAuthorize("@ss.hasPermi('inMonitoring:alertRule:query')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("查询预警详细规则") @ApiOperation("查询预警详细规则")
@Log(title = "【查询预警详细规则】", businessType = BusinessType.DELETE) @Log(title = "【查询预警详细规则】", businessType = BusinessType.OTHER)
public AjaxResult getInfo(@PathVariable("id") Long id) { public AjaxResult getInfo(@PathVariable("id") Long id) {
return success(alertRuleService.selectDetailAlertRuleById(id)); return success(alertRuleService.selectDetailAlertRuleById(id));
} }
@ -139,7 +139,7 @@ public class AlertRuleController extends BaseController {
@ApiOperation("获取预警参数") @ApiOperation("获取预警参数")
@PreAuthorize("@ss.hasPermi('inMonitoring:alertRule:byTable')") @PreAuthorize("@ss.hasPermi('inMonitoring:alertRule:byTable')")
@GetMapping("/byTable") @GetMapping("/byTable")
@Log(title = "【获取预警参数】", businessType = BusinessType.EXPORT) @Log(title = "【获取预警参数】", businessType = BusinessType.OTHER)
public AjaxResult getParamsByTableName() { public AjaxResult getParamsByTableName() {
return AjaxResult.success("获取预警参数成功",dictAlarmParamService.getParamsByTableName()); return AjaxResult.success("获取预警参数成功",dictAlarmParamService.getParamsByTableName());
} }

@ -30,7 +30,7 @@ public class equAssessment extends BaseController {
@PreAuthorize("@ss.hasPermi('inMonitoring:equAssessment:list')") @PreAuthorize("@ss.hasPermi('inMonitoring:equAssessment:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("设备评估信息") @ApiOperation("设备评估信息")
@Log(title = "设备评估与预测", businessType = BusinessType.UPDATE) @Log(title = "设备评估与预测", businessType = BusinessType.OTHER)
public TableDataInfo homeList() public TableDataInfo homeList()
{ {
startPage(); startPage();

@ -64,7 +64,7 @@ public class messageController extends BaseController {
@PreAuthorize("@ss.hasPermi('message:view')") @PreAuthorize("@ss.hasPermi('message:view')")
@ApiOperation("获取用户消息列表") @ApiOperation("获取用户消息列表")
@Log(title = "消息列表") @Log(title = "消息列表", businessType = BusinessType.OTHER)
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo getMessageList() { public TableDataInfo getMessageList() {
startPage(); startPage();

@ -310,6 +310,32 @@ public class AItokenService {
return "AI模型正在加载中,请稍等2-3分钟后再试。如果问题持续存在,可能需要检查系统资源配置。"; return "AI模型正在加载中,请稍等2-3分钟后再试。如果问题持续存在,可能需要检查系统资源配置。";
} }
} }
// 处理"length"状态 - 表示响应因长度限制被截断
else if ("length".equals(doneReason)) {
System.out.println("第 " + attempt + " 次尝试:模型响应因长度限制被截断");
// 尝试获取已生成的内容
JsonNode messageNode = rootNode.get("message");
if (messageNode != null) {
JsonNode contentNode = messageNode.get("content");
if (contentNode != null) {
String content = contentNode.asText();
if (content != null && !content.isEmpty()) {
System.out.println("尽管响应被截断,但已获取到部分回答内容,长度: " + content.length());
return content;
}
}
}
// 如果没有获取到内容,继续重试
if (attempt < maxRetries) {
long waitTime = 3000 * attempt;
System.out.println("等待 " + (waitTime/1000) + " 秒后重试...");
Thread.sleep(waitTime);
continue;
} else {
return "AI模型响应过长被截断,请尝试提出更具体的问题。";
}
}
// 只有当done_reason为stop时才表示真正结束 // 只有当done_reason为stop时才表示真正结束
else if (!"stop".equals(doneReason)) { else if (!"stop".equals(doneReason)) {
System.out.println("第 " + attempt + " 次尝试:模型返回未知的done_reason: " + doneReason); System.out.println("第 " + attempt + " 次尝试:模型返回未知的done_reason: " + doneReason);

@ -12,4 +12,6 @@ public class AlertDto {
private String status; private String status;
private String location; private String location;
private String inCharge; private String inCharge;
private String name;
private String equNumber;
} }

@ -0,0 +1,211 @@
package com.alops.system.domain.vo;
import java.util.Date;
import com.alops.common.annotation.Excel;
import com.alops.common.core.domain.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.mail.Message;
/**
* 故障统计对象 alert_message
*
* @author ruoyi
* @date 2025-09-04
*/
@Data
public class AlertMessages
{
private static final long serialVersionUID = 1L;
/** ID */
private Long id;
/** 设备ID */
@Excel(name = "设备ID")
private String equId;
/** 预警类型(枚举表名) */
@Excel(name = "预警类型(枚举表名)")
private String type;
/** 设备类型 */
@Excel(name = "设备类型")
private String equType;
@Excel(name = "设备名称")
private String name;
@Excel(name = "设备编号")
private String equNumber;
/** 解决方案 */
@Excel(name = "解决方案")
private String solution;
/** 故障级别(1-5级) */
@Excel(name = "预警级别(1-5级)")
private Long level;
/** 发生时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "添加日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date occurTime;
/** 处理人ID */
@Excel(name = "处理人ID")
private String handler;
/** 解决时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "添加日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date handleTime;
/** 处理状态(open、in_progress_closed) */
@Excel(name = "处理状态")
private String status;
@Excel(name = "信息批次")
private Integer batch;
@Excel(name ="预警信息")
private String message;
@JsonIgnore
@Excel(name ="预警规则id")
private Long alertRuleId;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setEquId(String equId)
{
this.equId = equId;
}
public String getEquId()
{
return equId;
}
public void setType(String type)
{
this.type = type;
}
public String getType()
{
return type;
}
public void setEquType(String equType)
{
this.equType = equType;
}
public String getEquType()
{
return equType;
}
public void setSolution(String solution)
{
this.solution = solution;
}
public String getSolution()
{
return solution;
}
public void setLevel(Long level)
{
this.level = level;
}
public Long getLevel()
{
return level;
}
public void setOccurTime(Date occurTime)
{
this.occurTime = occurTime;
}
public Date getOccurTime()
{
return occurTime;
}
public void setHandler(String handler)
{
this.handler = handler;
}
public String getHandler()
{
return handler;
}
public void setHandleTime(Date handleTime)
{
this.handleTime = handleTime;
}
public Date getHandleTime()
{
return handleTime;
}
public void setStatus(String status)
{
this.status = status;
}
public String getStatus()
{
return status;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("equId", getEquId())
.append("type", getType())
.append("equType", getEquType())
.append("solution", getSolution())
.append("level", getLevel())
.append("occurTime", getOccurTime())
.append("handler", getHandler())
.append("handleTime", getHandleTime())
.append("status", getStatus())
.append("batch",getBatch())
.toString();
}
}

@ -43,6 +43,7 @@ public class GatherJob implements Job {
// 1.状态为5时取消调度任务 // 1.状态为5时取消调度任务
if (rule.getStatus() == 5) { if (rule.getStatus() == 5) {
rule.setStatus(4); rule.setStatus(4);
scheduleRulesMapper.updateScheduleRules(rule);
Scheduler scheduler = context.getScheduler(); Scheduler scheduler = context.getScheduler();
JobKey jobKey = context.getJobDetail().getKey(); JobKey jobKey = context.getJobDetail().getKey();
// scheduler.deleteJob(jobKey); // scheduler.deleteJob(jobKey);
@ -123,7 +124,7 @@ public class GatherJob implements Job {
rule.setStatus(3); rule.setStatus(3);
scheduleRulesMapper.updateScheduleRules(rule); scheduleRulesMapper.updateScheduleRules(rule);
try { try {
String Content=String.format("采集任务整体执行失败,规则ID=%s,规则名称=%s,原因:%s", String Content=String.format("采集任务整体执行失败,规则ID=%s,规则名称=%s,原因:%s,已取消任务",
rule.getId(), rule.getRuleName(), e.getMessage()); rule.getId(), rule.getRuleName(), e.getMessage());
iAlertSenderService.sendInternalMessage("采集任务整体执行失败" ,Content,"2" ); iAlertSenderService.sendInternalMessage("采集任务整体执行失败" ,Content,"2" );

@ -2,6 +2,7 @@ package com.alops.system.mapper;
import com.alops.system.domain.AlertMessage; import com.alops.system.domain.AlertMessage;
import com.alops.system.domain.dto.AlertDto; import com.alops.system.domain.dto.AlertDto;
import com.alops.system.domain.vo.AlertMessages;
import com.alops.system.domain.vo.homeEquAlertMessageVo; import com.alops.system.domain.vo.homeEquAlertMessageVo;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
@ -44,7 +45,7 @@ public interface AlertMessageMapper
* @param alertMessage 故障统计 * @param alertMessage 故障统计
* @return 故障统计集合 * @return 故障统计集合
*/ */
public List<AlertMessage> selectAlertMessageList(AlertDto alertMessage); public List<AlertMessages> selectAlertMessageList(AlertDto alertMessage);
public List<homeEquAlertMessageVo> selectStaticAlertMessageList(); public List<homeEquAlertMessageVo> selectStaticAlertMessageList();
public ArrayList<AlertMessage> selectAlertMessageByEquId(String Equid); public ArrayList<AlertMessage> selectAlertMessageByEquId(String Equid);

@ -3,6 +3,7 @@ package com.alops.system.service;
import com.alops.system.domain.AlertMessage; import com.alops.system.domain.AlertMessage;
import com.alops.system.domain.dto.AlertDto; import com.alops.system.domain.dto.AlertDto;
import com.alops.system.domain.dto.AlertStatisticDto; import com.alops.system.domain.dto.AlertStatisticDto;
import com.alops.system.domain.vo.AlertMessages;
import com.alops.system.domain.vo.homeEquAlertMessageVo; import com.alops.system.domain.vo.homeEquAlertMessageVo;
import java.util.List; import java.util.List;
@ -30,7 +31,7 @@ public interface IAlertMessageService
* @param alertMessage 故障统计 * @param alertMessage 故障统计
* @return 故障统计集合 * @return 故障统计集合
*/ */
public List<AlertMessage> selectAlertMessageList(AlertDto alertMessage); public List<AlertMessages> selectAlertMessageList(AlertDto alertMessage);
public List<homeEquAlertMessageVo> selectStaticAlertMessageList(); public List<homeEquAlertMessageVo> selectStaticAlertMessageList();
public List<AlertMessage> selectAlertMessageListByEquId(String equId); public List<AlertMessage> selectAlertMessageListByEquId(String equId);

@ -11,6 +11,7 @@ import com.alops.system.domain.dto.AlertDto;
import com.alops.system.domain.dto.AlertStatisticDto; import com.alops.system.domain.dto.AlertStatisticDto;
import com.alops.system.domain.dto.LevelCountDto; import com.alops.system.domain.dto.LevelCountDto;
import com.alops.system.domain.dto.TypeCountDto; import com.alops.system.domain.dto.TypeCountDto;
import com.alops.system.domain.vo.AlertMessages;
import com.alops.system.domain.vo.homeEquAlertMessageVo; import com.alops.system.domain.vo.homeEquAlertMessageVo;
import com.alops.system.mapper.AlertMessageMapper; import com.alops.system.mapper.AlertMessageMapper;
import com.alops.system.service.IAlertMessageService; import com.alops.system.service.IAlertMessageService;
@ -48,7 +49,7 @@ public class AlertMessageServiceImpl implements IAlertMessageService
* @return 故障统计 * @return 故障统计
*/ */
@Override @Override
public List<AlertMessage> selectAlertMessageList(AlertDto alertMessage) public List<AlertMessages> selectAlertMessageList(AlertDto alertMessage)
{ {
return alertMessageMapper.selectAlertMessageList(alertMessage); return alertMessageMapper.selectAlertMessageList(alertMessage);
} }

@ -87,9 +87,9 @@ public class EquBaseServiceImpl implements IEquBaseService
vo.setRiskGrade(switch (riskLevel) { vo.setRiskGrade(switch (riskLevel) {
case 1 -> "无风险"; case 1 -> "无风险";
case 2 -> "低"; case 2 -> "低风险";
case 3 -> "中"; case 3 -> "中风险";
case 4 -> "高"; case 4 -> "高风险";
default -> "未知"; default -> "未知";
}); });

@ -205,7 +205,7 @@ public class ScheduleRulesServiceImpl implements IScheduleRulesService {
oidMap.put(dev.getEquManuId(), equOidMapper.findByManuIdAndStatus(dev.getEquManuId())); oidMap.put(dev.getEquManuId(), equOidMapper.findByManuIdAndStatus(dev.getEquManuId()));
} }
// 并发采集 // 并发采集
ExecutorService executor = Executors.newFixedThreadPool(10); ExecutorService executor = Executors.newFixedThreadPool(12);
List<Future<GatherEntities>> futures = new ArrayList<>(); List<Future<GatherEntities>> futures = new ArrayList<>();
for (EquBase device : devices) { for (EquBase device : devices) {
futures.add(executor.submit(() -> { futures.add(executor.submit(() -> {
@ -271,12 +271,12 @@ public class ScheduleRulesServiceImpl implements IScheduleRulesService {
gatherValidator.validateBeforeDbOperation(successList, failed, oidMap); gatherValidator.validateBeforeDbOperation(successList, failed, oidMap);
List<String> failedEquIds = validationResult.getFailed().stream() // List<String> failedEquIds = validationResult.getFailed().stream()
.map(f -> f.get("equId")) // .map(f -> f.get("equId"))
.collect(Collectors.toList()); // .collect(Collectors.toList());
// 事务内:删除成功设备依附表 + 插入成功设备数据 + 执行预警 // 事务内:删除成功设备依附表 + 插入成功设备数据 + 执行预警
deleteAllEquipmentData(failedEquIds); // 删除依附表,不含 equ_gather deleteAllEquipmentData(validationResult.getSuccessList()); // 删除依附表,不含 equ_gather
// 插入成功设备数据(内部失败会抛异常,触发事务回滚) // 插入成功设备数据(内部失败会抛异常,触发事务回滚)
persistAndUpdate(validationResult.getSuccessList()); persistAndUpdate(validationResult.getSuccessList());
@ -287,33 +287,64 @@ public class ScheduleRulesServiceImpl implements IScheduleRulesService {
return Code.SUCCESS; return Code.SUCCESS;
} }
@Transactional(rollbackFor = Exception.class) // @Transactional(rollbackFor = Exception.class)
public void deleteAllEquipmentData(List<String> failedEquIds) { // public void deleteAllEquipmentData(List<String> failedEquIds) {
// 1 查询失败设备最新采集ID // // 1 查询失败设备最新采集ID
List<String> excludeGatherIds = failedEquIds == null || failedEquIds.isEmpty() ? // List<String> excludeGatherIds = failedEquIds == null || failedEquIds.isEmpty() ?
Collections.emptyList() : equGatherMapper.selectLatestGatherIdsByEquIds(failedEquIds); // Collections.emptyList() : equGatherMapper.selectLatestGatherIdsByEquIds(failedEquIds);
//
// 2 依附表列表 // // 2 依附表列表
String[] dependentTables = {"equ_interface", "equ_routing", "equ_veneer", "equ_vlan"}; // String[] dependentTables = {"equ_interface", "equ_routing", "equ_veneer", "equ_vlan"};
//
for (String table : dependentTables) { // for (String table : dependentTables) {
int deleted; // int deleted;
if (excludeGatherIds.isEmpty()) { // if (excludeGatherIds.isEmpty()) {
// 没有失败设备,直接清空表 // // 没有失败设备,直接清空表
deleted = jdbcTemplate.update("DELETE FROM " + table); // deleted = jdbcTemplate.update("DELETE FROM " + table);
} else { // } else {
// 使用占位符方式安全删除 // // 使用占位符方式安全删除
String inSql = excludeGatherIds.stream().map(id -> "?").collect(Collectors.joining(",")); // String inSql = excludeGatherIds.stream().map(id -> "?").collect(Collectors.joining(","));
String sql = String.format("DELETE FROM %s WHERE equ_gather_id NOT IN (%s)", table, inSql); // String sql = String.format("DELETE FROM %s WHERE equ_gather_id NOT IN (%s)", table, inSql);
deleted = jdbcTemplate.update(sql, excludeGatherIds.toArray()); // deleted = jdbcTemplate.update(sql, excludeGatherIds.toArray());
} // }
log.info("表 {} 删除 {} 条数据,保留失败设备采集ID: {}", table, deleted, excludeGatherIds); // log.info("表 {} 删除 {} 条数据,保留失败设备采集ID: {}", table, deleted, excludeGatherIds);
} // }
//
// log.info("依附表数据删除完成,共保留 {} 个失败设备最新采集ID", excludeGatherIds.size());
// }
@Transactional(rollbackFor = Exception.class)
public void deleteAllEquipmentData(List<GatherEntities> successList) {
// 1 提取成功设备ID列表
List<String> successEquIds = successList.stream()
.map(g -> g.getEquGather().getEquId())
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
// 2 查询这些设备的最新采集ID(要保留的)
List<String> latestGatherIds = equGatherMapper.selectLatestGatherIdsByEquIds(successEquIds);
if (latestGatherIds == null || latestGatherIds.isEmpty()) {
log.warn("未查询到成功设备的最新采集ID,跳过删除操作");
return;
}
log.info("依附表数据删除完成,共保留 {} 个失败设备最新采集ID", excludeGatherIds.size()); // 3 依附表列表
String[] dependentTables = {"equ_interface", "equ_routing", "equ_veneer", "equ_vlan"};
// 4 拼 SQL: 删除所有 成功设备
String placeholders = latestGatherIds.stream().map(id -> "?").collect(Collectors.joining(","));
for (String table : dependentTables) {
String sql = String.format("DELETE FROM %s WHERE equ_gather_id IN (%s)", table, placeholders);
int deleted = jdbcTemplate.update(sql, latestGatherIds.toArray());
log.info("表 {} 删除旧数据 {} 条)", table, deleted);
} }
log.info("✅ 成功清理依附表数据,");
}
/** /**
* 批量落库更新采集次数执行最新预警 * 批量落库更新采集次数执行最新预警
* 事务保证如果任何步骤失败整个操作回滚 * 事务保证如果任何步骤失败整个操作回滚

@ -45,17 +45,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<sql id="selectAlertMessageVo"> <sql id="selectAlertMessageVo">
SELECT am.id, SELECT am.id,
am.equ_id, am.equ_id AS equId ,
am.type, am.type,
am.equ_type, am.equ_type AS equType,
am.solution, am.solution,
am.level, am.level,
am.occur_time, am.occur_time AS occurTime,
am.handler, am.handler,
am.handle_time, am.handle_time AS handleTime,
am.status, am.status,
am.batch, am.batch,
am.message am.message,
eb.name,
eb.equ_number AS equNumber
FROM alert_message am FROM alert_message am
LEFT JOIN equ_base eb ON am.equ_id = eb.id LEFT JOIN equ_base eb ON am.equ_id = eb.id
</sql> </sql>
@ -64,7 +66,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select a.id, g.equ_id, type, equ_type, solution, level, occur_time, handler, handle_time, status,batch,message from alert_message a LEFT JOIN equ_gather g ON a.equ_id = g.equ_id select a.id, g.equ_id, type, equ_type, solution, level, occur_time, handler, handle_time, status,batch,message from alert_message a LEFT JOIN equ_gather g ON a.equ_id = g.equ_id
</sql> </sql>
<select id="selectAlertMessageList" parameterType="AlertDto" resultMap="AlertMessageResult"> <select id="selectAlertMessageList" parameterType="AlertDto" resultType="AlertMessages">
<include refid="selectAlertMessageVo"/> <include refid="selectAlertMessageVo"/>
<where> <where>
<!-- 时间范围 --> <!-- 时间范围 -->
@ -82,6 +84,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<!-- 设备管理员精确匹配 --> <!-- 设备管理员精确匹配 -->
<if test="inCharge != null and inCharge != ''"> AND eb.in_charge = #{inCharge} </if> <if test="inCharge != null and inCharge != ''"> AND eb.in_charge = #{inCharge} </if>
<!-- ✅ 设备名称模糊匹配 -->
<if test="name != null and name != ''">
AND eb.name LIKE CONCAT('%', #{name}, '%')
</if>
<!-- ✅ 设备编号精准匹配 -->
<if test="equNumber != null and equNumber != ''">
AND eb.equ_number = #{equNumber}
</if>
</where> </where>
<!-- 按 batch 从大到小排序 --> <!-- 按 batch 从大到小排序 -->
ORDER BY am.batch DESC ORDER BY am.batch DESC

@ -1,5 +1,5 @@
# 页面标题 # 页面标题
VUE_APP_TITLE = 中国烟草 VUE_APP_TITLE = 唐山烟草网络设备智能监管平台
# 开发环境配置 # 开发环境配置
ENV = 'development' ENV = 'development'

@ -1,5 +1,5 @@
# 页面标题 # 页面标题
VUE_APP_TITLE = 中国烟草 VUE_APP_TITLE = 唐山烟草网络设备智能监管平台
# 生产环境配置 # 生产环境配置
ENV = 'production' ENV = 'production'

@ -1,7 +1,7 @@
{ {
"name": "ruoyi", "name": "ruoyi",
"version": "3.9.0", "version": "3.9.0",
"description": "中国烟草", "description": "唐山烟草网络设备智能监管平台",
"author": "若依", "author": "若依",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {

@ -4,9 +4,10 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit"> <meta name="renderer" content="webkit">
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<title><%= webpackConfig.name %></title> <title>唐山烟草网络设备智能监管平台</title>
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]--> <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
<style> <style>
html, html,

@ -35,7 +35,7 @@ export default {
}, },
data() { data() {
return { return {
title: process.env.VUE_APP_TITLE, title: '中国烟草',
logo: logoImg logo: logoImg
} }
} }

@ -194,7 +194,7 @@ class WebSocketClient {
title: message.title || '系统通知', title: message.title || '系统通知',
message: message.content, message: message.content,
type: 'info', type: 'info',
duration: 1000000, // 10秒后自动关闭 duration: 60000, // 60秒后自动关闭
showClose: true, showClose: true,
onClick: () => { onClick: () => {
// 可以在这里添加点击通知后的处理逻辑 // 可以在这里添加点击通知后的处理逻辑

@ -79,21 +79,23 @@ export default {
methods: { methods: {
sendMessage() { sendMessage() {
if (!this.newMessage.trim()) return; if (!this.newMessage.trim()) return;
console.log("%c 🍃: sendMessage -> this.newMessage ", "font-size:16px;background-color:#46f583;color:black;", this.newMessage)
// //
this.messages.push({ this.messages.push({
text: this.newMessage, text: this.newMessage,
sender: 'customer', sender: 'customer',
time: this.formatTime(new Date()) time: this.formatTime(new Date())
}); });
let newMessageContent = this.newMessage;
// //
setTimeout(() => { setTimeout(() => {
this.autoReply(this.newMessage); this.autoReply(newMessageContent);
}, 1000); }, 1000);
this.newMessage = ''; this.newMessage = '';
}, },
async autoReply(userMessage) { async autoReply(userMessage) {
console.log("%c 🇱🇺: autoReply -> userMessage ", "font-size:16px;background-color:#c70b31;color:white;", userMessage)
let replyText = ''; let replyText = '';
let res = await knowledgeAsk({question: userMessage }); let res = await knowledgeAsk({question: userMessage });
if (res.code == 200) { if (res.code == 200) {

@ -22,7 +22,7 @@
<el-table-column label="文件名称" align="center" key="source" prop="source" :show-overflow-tooltip="true" /> <el-table-column label="文件名称" align="center" key="source" prop="source" :show-overflow-tooltip="true" />
<el-table-column label="更新时间" align="center" prop="uploadTime" width="160"> <el-table-column label="更新时间" align="center" prop="uploadTime" width="160">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ parseTime(scope.row.uploadTime) }}</span> <span>{{ formatISOTime(scope.row.uploadTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
@ -56,6 +56,8 @@
:data="{ source: form.source }" :data="{ source: form.source }"
:on-preview="handlePreview" :on-preview="handlePreview"
:on-remove="handleRemove" :on-remove="handleRemove"
:on-error="handleUploadError"
:before-upload="beforeUpload"
:file-list="fileList" :file-list="fileList"
:headers="headers" :headers="headers"
:auto-upload="false"> :auto-upload="false">
@ -298,6 +300,22 @@ export default {
this.$modal.msgSuccess("删除成功") this.$modal.msgSuccess("删除成功")
}).catch(() => {}) }).catch(() => {})
}, },
/** 格式化ISO时间字符串 */
formatISOTime(isoString) {
if (!isoString) return '';
const date = new Date(isoString);
if (isNaN(date.getTime())) return isoString;
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
},
/** 导出按钮操作 */ /** 导出按钮操作 */
handleExport() { handleExport() {
this.download('system/user/export', { this.download('system/user/export', {
@ -318,6 +336,31 @@ export default {
handleFileUploadProgress(event, file, fileList) { handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true this.upload.isUploading = true
}, },
//
beforeUpload(file) {
const isDocx = file.name.endsWith('.docx');
const isTxt = file.name.endsWith('.txt');
const isLt5M = file.size / 1024 / 1024 < 5;
if (!isDocx && !isTxt) {
this.$message.error('只允许上传docx/txt格式的文件!');
return false;
}
if (!isLt5M) {
this.$message.error('文件大小不能超过5MB!');
return false;
}
return true;
},
//
handleUploadError(err, file, fileList) {
this.upload.isUploading = false;
//
this.$modal.msgError("上传失败,请重试");
console.error('上传失败:', err);
},
// //
handleFileSuccess(response, file, fileList) { handleFileSuccess(response, file, fileList) {
this.upload.isUploading = false; this.upload.isUploading = false;

@ -21,6 +21,7 @@
<el-col :span="24"> <el-col :span="24">
<el-form-item label="采集间隔" prop="frequency"> <el-form-item label="采集间隔" prop="frequency">
<el-input-number v-model="queryParams.frequency" controls-position="right" :min="1"></el-input-number> <el-input-number v-model="queryParams.frequency" controls-position="right" :min="1"></el-input-number>
<span> 分钟</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">

@ -20,16 +20,16 @@
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['device:deviceManufacturer:add']">新增</el-button> <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['device:deviceManu:add']">新增</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['device:deviceManufacturer:remove']">删除</el-button> <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['device:deviceManu:remove']">删除</el-button>
</el-col> </el-col>
<!-- <el-col :span="1.5"> <!-- <el-col :span="1.5">
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['device:deviceManufacturer:import']">导入</el-button> <el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['device:deviceManu:import']">导入</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['device:deviceManufacturer:export']">导出</el-button> <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['device:deviceManu:export']">导出</el-button>
</el-col> --> </el-col> -->
</el-row> </el-row>
@ -57,8 +57,8 @@
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['device:deviceManufacturer:edit']">修改</el-button> <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['device:deviceManu:modify']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:deviceManufacturer:remove']">删除</el-button> <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:deviceManu:delete']">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>

@ -47,8 +47,8 @@
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope" v-if="scope.row.id !== 1"> <template slot-scope="scope" v-if="scope.row.id !== 1">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['device:deviceType:edit']">修改</el-button> <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['device:deviceType:modify']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:deviceType:remove']">删除</el-button> <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:deviceType:delete']">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>

@ -26,26 +26,26 @@
<span class="info-label"> <span class="info-label">
<i class="fas fa-layer-group"></i> 设备级别 <i class="fas fa-layer-group"></i> 设备级别
</span> </span>
<span class="info-value">{{cardData.deviceLevel || '暂无'}}</span> <span class="info-value" :title="cardData.deviceLevel || '暂无'">{{cardData.deviceLevel || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-map-marker-alt"></i> 安装位置 <i class="fas fa-map-marker-alt"></i> 安装位置
</span> </span>
<span class="info-value">{{cardData.location || '暂无'}}</span> <span class="info-value" :title="cardData.location || '暂无'">{{cardData.location || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-tag"></i> 品牌型号 <i class="fas fa-tag"></i> 品牌型号
</span> </span>
<span class="info-value">{{cardData.brand || '暂无'}}</span> <span class="info-value" :title="cardData.brand || '暂无'">{{cardData.brand || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-heartbeat"></i> 带外IP <i class="fas fa-heartbeat"></i> 带外IP
<!-- <i class="fas fa-heartbeat"></i> 带内IP --> <!-- <i class="fas fa-heartbeat"></i> 带内IP -->
</span> </span>
<span class="info-value">{{cardData.ip || '暂无'}}</span> <span class="info-value" :title="cardData.ip || '暂无'">{{cardData.ip || '暂无'}}</span>
</div> </div>
</div> </div>
</div> </div>
@ -420,6 +420,7 @@ export default {
.info-label i { .info-label i {
font-size: 12px; font-size: 12px;
width: 8px;
color: #4299e1; color: #4299e1;
} }
@ -427,6 +428,12 @@ export default {
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
color: #2d3748; color: #2d3748;
padding-left: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: help;
width: 90px;
} }
.chart-container { .chart-container {

@ -26,31 +26,31 @@
<span class="info-label"> <span class="info-label">
<i class="fas fa-heartbeat"></i> 设备编号 <i class="fas fa-heartbeat"></i> 设备编号
</span> </span>
<span class="info-value">{{details.equNumber || '暂无'}}</span> <span class="info-value" :title="details.equNumber || '暂无'">{{details.equNumber || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-layer-group"></i> 固件版本 <i class="fas fa-layer-group"></i> 固件版本
</span> </span>
<span class="info-value">{{details.version || '暂无'}}</span> <span class="info-value" :title="details.version || '暂无'">{{details.version || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-layer-group"></i> 设备级别 <i class="fas fa-layer-group"></i> 设备级别
</span> </span>
<span class="info-value">{{details.deviceLevel || '暂无'}}</span> <span class="info-value" :title="(details.deviceLevel || '暂无') + '级'">{{details.deviceLevel || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-map-marker-alt"></i> 安装位置 <i class="fas fa-map-marker-alt"></i> 安装位置
</span> </span>
<span class="info-value">{{details.location || '暂无'}}</span> <span class="info-value" :title="details.location || '暂无'">{{details.location || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-tag"></i> 品牌型号 <i class="fas fa-tag"></i> 品牌型号
</span> </span>
<span class="info-value">{{details.brand || '暂无'}}</span> <span class="info-value" :title="details.brand || '暂无'">{{details.brand || '暂无'}}</span>
</div> </div>
</div> </div>
@ -62,33 +62,33 @@
<span class="info-label"> <span class="info-label">
<i class="fas fa-layer-group"></i> 生产厂商名称 <i class="fas fa-layer-group"></i> 生产厂商名称
</span> </span>
<span class="info-value">{{details.equManuName || '暂无'}}</span> <span class="info-value" :title="details.equManuName || '暂无'">{{details.equManuName || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-map-marker-alt"></i> 供货商名称 <i class="fas fa-map-marker-alt"></i> 供货商名称
</span> </span>
<span class="info-value">{{details.supplierName || '暂无'}}</span> <span class="info-value" :title="details.supplierName || '暂无'">{{details.supplierName || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-tag"></i> 供货商联系人 <i class="fas fa-tag"></i> 供货商联系人
</span> </span>
<span class="info-value">{{ details.contactBy || '暂无'}}</span> <span class="info-value" :title="details.contactBy || '暂无'">{{ details.contactBy || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-heartbeat"></i> 供货商联系电话 <i class="fas fa-heartbeat"></i> 供货商联系电话
</span> </span>
<span class="info-value">{{ details.contactWay || '暂无'}}</span> <span class="info-value" :title="details.contactWay || '暂无'">{{ details.contactWay || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-heartbeat"></i> 质保时间 <i class="fas fa-heartbeat"></i> 质保时间
</span> </span>
<span class="info-value">{{details.warranty || '暂无'}}</span> <span class="info-value" :title="details.warranty || '暂无'">{{details.warranty || '暂无'}}</span>
</div> </div>
</div> </div>
@ -100,7 +100,7 @@
<span class="info-label"> <span class="info-label">
<i class="fas fa-layer-group"></i> 带外管理IP <i class="fas fa-layer-group"></i> 带外管理IP
</span> </span>
<span class="info-value">{{details.ip || '暂无'}}</span> <span class="info-value" :title="details.ip || '暂无'">{{details.ip || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
@ -112,13 +112,13 @@
<span class="info-label"> <span class="info-label">
<i class="fas fa-layer-group"></i> 安装日期 <i class="fas fa-layer-group"></i> 安装日期
</span> </span>
<span class="info-value">{{details.installDate || '暂无'}}</span> <span class="info-value" :title="details.installDate || '暂无'">{{details.installDate || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-layer-group"></i> 管理员 <i class="fas fa-layer-group"></i> 管理员
</span> </span>
<span class="info-value">{{details.inCharge || '暂无'}}</span> <span class="info-value" :title="details.inCharge || '暂无'">{{details.inCharge || '暂无'}}</span>
</div> </div>
</div> </div>
@ -129,19 +129,19 @@
<span class="info-label"> <span class="info-label">
<i class="fas fa-layer-group"></i> 设备持续运行时长 <i class="fas fa-layer-group"></i> 设备持续运行时长
</span> </span>
<span class="info-value">{{formatDuration(details.contWorkPeriod) || '暂无'}}</span> <span class="info-value" :title="formatDuration(details.contWorkPeriod) || '暂无'">{{formatDuration(details.contWorkPeriod) || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-layer-group"></i> 待处理预警数 <i class="fas fa-layer-group"></i> 待处理预警数
</span> </span>
<span class="info-value">{{details.unhandledAlertCount || '暂无'}}</span> <span class="info-value" :title="details.unhandledAlertCount || '暂无'">{{details.unhandledAlertCount || '暂无'}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label"> <span class="info-label">
<i class="fas fa-layer-group"></i> 预警总数 <i class="fas fa-layer-group"></i> 预警总数
</span> </span>
<span class="info-value">{{details.alertCount || '暂无'}}</span> <span class="info-value" :title="details.alertCount || '暂无'">{{details.alertCount || '暂无'}}</span>
</div> </div>
</div> </div>
</div> </div>
@ -175,23 +175,102 @@
</el-col> </el-col>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-col :span="12"> <div class="health-indicators">
<div ref="usedmemory" style="height: 150px" /> <el-row :gutter="16">
</el-col> <!-- 温度 -->
<el-col :span="12"> <el-col :span="8">
<div ref="usedmemory2" style="height: 150px" /> <div class="health-card">
</el-col> <div class="health-header">
<div class="health-icon" :class="getTemperatureClass(details.temperature)">
<el-col :span="8"> <i class="el-icon-odometer"></i>
<div ref="usedmemory3" style="height: 120px" /> </div>
</el-col> <div class="health-label">当前温度</div>
<el-col :span="8"> </div>
<div ref="usedmemory4" style="height: 120px" /> <div class="health-circle" :class="getTemperatureClass(details.temperature)">
</el-col> <div class="health-value" :class="getTemperatureClass(details.temperature)">{{details.temperature || '暂无'}}</div>
<el-col :span="8"> <div class="health-unit"></div>
<div ref="usedmemory5" style="height: 120px" /> </div>
</el-col> </div>
</el-col>
<!-- CPU使用率 -->
<el-col :span="8">
<div class="health-card">
<div class="health-header">
<div class="health-icon" :class="getUtilizationClass(details.cpuUtilization)">
<i class="el-icon-cpu"></i>
</div>
<div class="health-label">CPU使用率</div>
</div>
<div class="health-circle" :class="getUtilizationClass(details.cpuUtilization)">
<div class="health-value" :class="getUtilizationClass(details.cpuUtilization)">{{details.cpuUtilization || '暂无'}}</div>
<div class="health-unit">%</div>
</div>
</div>
</el-col>
<!-- 内存使用率 -->
<el-col :span="8">
<div class="health-card">
<div class="health-header">
<div class="health-icon" :class="getUtilizationClass(details.memoryUtilization)">
<i class="el-icon-thumb"></i>
</div>
<div class="health-label">内存使用率</div>
</div>
<div class="health-circle" :class="getUtilizationClass(details.memoryUtilization)">
<div class="health-value" :class="getUtilizationClass(details.memoryUtilization)">{{details.memoryUtilization || '暂无'}}</div>
<div class="health-unit">%</div>
</div>
</div>
</el-col>
<!-- 健康度 -->
<el-col :span="8">
<div class="health-card">
<div class="health-header">
<div class="health-icon" :class="getHealthClass(Number(details.health))">
<i class="el-icon-orange"></i>
</div>
<div class="health-label">当前健康度</div>
</div>
<div class="health-circle" :class="getHealthClass(Number(details.health))">
<div class="health-value" :class="getHealthClass(Number(details.health))">{{ Number(details.health) == 1 ? '健康' : Number(details.health) == 2 ? '良好': Number(details.health) == 3 ? '一般': Number(details.health) == 4 ? '需维护' : '暂无' }}</div>
<div class="health-unit"></div>
</div>
</div>
</el-col>
<!-- volIn -->
<el-col :span="8">
<div class="health-card">
<div class="health-header">
<div class="health-icon system-color">
<i class="el-icon-s-data"></i>
</div>
<div class="health-label">当前流量输入值</div>
</div>
<div class="health-circle system-color">
<div class="health-value system-color">{{details.volIn ? parseInt(details.volIn) : '暂无'}}</div>
<div class="health-unit">L/min</div>
</div>
</div>
</el-col>
<!-- volOut -->
<el-col :span="8">
<div class="health-card">
<div class="health-header">
<div class="health-icon system-color">
<i class="el-icon-s-data"></i>
</div>
<div class="health-label">当前流量输出值</div>
</div>
<div class="health-circle system-color">
<div class="health-value system-color">{{details.volOut ? parseInt(details.volOut) : '暂无'}}</div>
<div class="health-unit">L/min</div>
</div>
</div>
</el-col>
</el-row>
</div>
</el-col> </el-col>
<!-- 图表模块已删除 -->
</el-row> </el-row>
</div> </div>
@ -206,19 +285,19 @@
</div> </div>
<div class="metrics-grid"> <div class="metrics-grid">
<div class="bottom-item scroll-height-500" v-if="tabIndex == 0"> <div class="bottom-item scroll-height-680" v-if="tabIndex == 0">
<History :dsId="dsId"/> <History :dsId="dsId"/>
</div> </div>
<div class="bottom-item scroll-height-500" v-if="tabIndex == 1"> <div class="bottom-item scroll-height-680" v-if="tabIndex == 1">
<Interface :dsId="dsId"/> <Interface :dsId="dsId"/>
</div> </div>
<div class="bottom-item scroll-height-500" v-if="tabIndex == 2"> <div class="bottom-item scroll-height-680" v-if="tabIndex == 2">
<Vlan :dsId="dsId"/> <Vlan :dsId="dsId"/>
</div> </div>
<div class="bottom-item scroll-height-500" v-if="tabIndex == 3"> <div class="bottom-item scroll-height-680" v-if="tabIndex == 3">
<Routing :dsId="dsId"/> <Routing :dsId="dsId"/>
</div> </div>
<div class="bottom-item scroll-height-500" v-if="tabIndex == 4"> <div class="bottom-item scroll-height-680" v-if="tabIndex == 4">
<Veneer :dsId="dsId"/> <Veneer :dsId="dsId"/>
</div> </div>
</div> </div>
@ -247,7 +326,7 @@ export default {
components: { History, Interface, Vlan, Routing, LineChart, Veneer}, components: { History, Interface, Vlan, Routing, LineChart, Veneer},
data() { data() {
return { return {
DateValue: [dayjs().subtract(1, 'month').format('YYYY-MM-DD HH:mm:ss'),dayjs().format('YYYY-MM-DD HH:mm:ss')], DateValue: [dayjs().subtract(1, 'week').format('YYYY-MM-DD HH:mm:ss'),dayjs().format('YYYY-MM-DD HH:mm:ss')],
selectedTab: 1, selectedTab: 1,
tabs: [ tabs: [
{ name: '历史预警' }, { name: '历史预警' },
@ -289,306 +368,7 @@ mounted() {
// //
let details = this.historyQueryData; let details = this.historyQueryData;
const combinedPerformanceChart = echarts.init(document.getElementById('combinedPerformanceChart')); const combinedPerformanceChart = echarts.init(document.getElementById('combinedPerformanceChart'));
const usedmemory = echarts.init(this.$refs.usedmemory, "macarons") // usedmemory
const usedmemory2 = echarts.init(this.$refs.usedmemory2, "macarons")
const usedmemory3 = echarts.init(this.$refs.usedmemory3, "macarons")
const usedmemory4 = echarts.init(this.$refs.usedmemory4, "macarons")
const usedmemory5 = echarts.init(this.$refs.usedmemory5, "macarons")
const chartData = { min: 0, max: 100, value: 70 };
usedmemory.setOption({
series: [
{
type: 'gauge',
center: ['50%', '60%'],
radius: '90%',
min: chartData.min,
max: chartData.max,
startAngle: 220,
endAngle: -40,
splitNumber: 8,
axisLine: {
lineStyle: {
color: [
[0.25, '#7afeaf'],
[0.5, '#58d9f9'],
[0.75, '#fbdd5e'],
[1, '#f03b44'],
],
width: 10,
},
},
splitLine: {
// 线
show: true,
length: 15,
distance: 10,
lineStyle: {
width: 2,
color: 'auto',
},
},
axisTick: {
// 线线
show: true,
lineStyle: {
width: 2,
color: 'auto',
},
length: 10,
distance: 10,
},
axisLabel: false,
detail: {
fontSize: '16',
formatter: '{value}℃',
color: 'auto',
offsetCenter: ['0', '0%'],
},
pointer: {
icon: 'triangle',
show: true,
offsetCenter: [0, '-70%'],
itemStyle: {
color: 'auto',
},
length: '10%',
width: '3%',
},
data: [
{
value: this.details.temperature,
name: '温度',
title: {
show: true,
color: '#606266',
offsetCenter: [0, '70%'],
fontSize: 18,
}
},
],
}
]
})
usedmemory2.setOption({
series: [
{
type: 'gauge',
center: ['50%', '60%'],
radius: '90%',
min: chartData.min,
max: chartData.max,
startAngle: 220,
endAngle: -40,
splitNumber: 8,
axisLine: {
lineStyle: {
color: [
[0.25, '#f03b44'],
[0.5, '#fbdd5e'],
[0.75, '#58d9f9'],
[1, '#7afeaf'],
],
width: 10,
},
},
splitLine: {
// 线
show: true,
length: 15,
distance: 10,
lineStyle: {
width: 2,
color: 'auto',
},
},
axisTick: {
// 线线
show: true,
lineStyle: {
width: 2,
color: 'auto',
},
length: 10,
distance: 10,
},
axisLabel: false,
detail: {
fontSize: '16',
formatter: '{value}',
color: 'auto',
offsetCenter: ['0', '0%'],
},
pointer: {
icon: 'triangle',
show: true,
offsetCenter: [0, '-70%'],
itemStyle: {
color: 'auto',
},
length: '10%',
width: '3%',
},
data: [
{
value: this.details.health == 1 ? '100' : this.details.health == 2 ? '75': this.details.health == 3 ? '50': this.details.health == 4 ? '25' : '0',
name: '健康度',
title: {
show: true,
color: '#606266',
offsetCenter: [0, '70%'],
fontSize: 18,
}
},
],
}
]
})
usedmemory3.setOption({
title: [
{
text: 'CPU占用',
left: '45%',
top: '55%',
textAlign: 'center',
textStyle: {
fontSize: '14',
fontWeight: '400',
color: '#6AA0E4',
textAlign: 'center',
textShadowColor: '#000',
},
},
],
series: {
type: 'pie',
radius: ['90%', "100%"],
hoverAnimation: false,
data: [
{
value: this.details.cpuUtilization,
label: {
normal: {
color: '#6AA0E4',
fontSize: 22,
fontWeight: 'bold',
formatter: function(params) {
return params.value + '%';
},
position: 'center',
show: true,
}
},
itemStyle: {
normal: {
color: '#6AA0E4'
}
}
},{
value: 100-this.details.cpuUtilization,
name: '',
labelLine: {
show: false
},
itemStyle: {
normal: {
color: '#D8D8D8'
},
emphasis:{
color:'#D8D8D8'
}
}
}]
}
})
usedmemory4.setOption({
title: [
{
text: '内存使用率',
left: '45%',
top: '55%',
textAlign: 'center',
textStyle: {
fontSize: '14',
fontWeight: '400',
color: '#6AA0E4',
textAlign: 'center',
textShadowColor: '#000',
},
},
],
series: {
type: 'pie',
radius: ['90%', "100%"],
hoverAnimation: false,
data: [
{
value: this.details.memoryUtilization,
label: {
normal: {
color: '#6AA0E4',
fontSize: 22,
fontWeight: 'bold',
formatter: function(params) {
return params.value + '%';
},
position: 'center',
show: true,
}
},
itemStyle: {
normal: {
color: '#6AA0E4'
}
}
},{
value: 100-this.details.memoryUtilization,
name: '',
labelLine: {
show: false
},
itemStyle: {
normal: {
color: '#D8D8D8'
},
emphasis:{
color:'#D8D8D8'
}
}
}]
}
})
usedmemory5.setOption({
series: [
{
type: 'pie',
radius: [0, '100%'],
center: ['50%', '50%'],
label: {
position: 'inside',
formatter: '{b}\n{c}',
color: '#30465D'
},
labelLine: {
length: 5,
length2: 5
},
data: [{
name: '输入',
value: this.details.volIn
},
{
name: '输出',
value: this.details.volOut
}
]
}
]
})
combinedPerformanceChart.setOption({ combinedPerformanceChart.setOption({
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
@ -602,42 +382,20 @@ mounted() {
params.forEach(function(item) { params.forEach(function(item) {
let value = item.value; let value = item.value;
let unit = ''; let unit = '';
// //
if (item.seriesName === '设备温度') { if (item.seriesName === '设备温度') {
unit = '℃'; unit = '℃';
} else if (item.seriesName === '健康度') { } else {
// - 访 unit = '%';
// }
let originalValue;
switch(value) {
case 100: originalValue = 1; break;
case 75: originalValue = 2; break;
case 50: originalValue = 3; break;
case 25: originalValue = 4; break;
default: originalValue = 0;
}
let statusText = '';
switch(originalValue) {
case 1: statusText = '健康'; break;
case 2: statusText = '良好'; break;
case 3: statusText = '一般'; break;
case 4: statusText = '需维护'; break;
default: statusText = '未知';
}
result += item.marker + item.seriesName + ': ' + value + '% (' + statusText + ')<br/>';
return;
} else {
unit = '%';
}
result += item.marker + item.seriesName + ': ' + value + unit + '<br/>'; result += item.marker + item.seriesName + ': ' + value + unit + '<br/>';
}); });
return result; return result;
} }
}, },
legend: { legend: {
data: ['设备温度', 'CPU使用率', '内存使用率', '健康度'], data: ['设备温度', 'CPU使用率', '内存使用率'],
textStyle: { textStyle: {
color: '#718096' color: '#718096'
} }
@ -764,43 +522,6 @@ mounted() {
}] }]
} }
} }
},
{
name: '健康度',
type: 'bar',
// 1->100, 2->75, 3->50, 4->25
// 使
data: details.healthList.map(value => {
const valueMap = {1: 100, 2: 75, 3: 50, 4: 25};
// 使value
return {
value: valueMap[value] || 0,
originalValue: value
};
}),
itemStyle: {
color: function(params) {
//
const originalValue = params.data && params.data.originalValue !== undefined ?
params.data.originalValue : params.value;
// 使switchcasebreak
switch(originalValue) {
case 1: return '#48bb78'; // - 绿
case 2: return '#4299e1'; // -
case 3: return '#ed8936'; // -
case 4: return '#f56565'; // -
default: return '#a0aec0'; //
}
}
},
barWidth: '40%',
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
} }
] ]
}); });
@ -809,8 +530,6 @@ mounted() {
// //
window.addEventListener('resize', function() { window.addEventListener('resize', function() {
combinedPerformanceChart.resize(); combinedPerformanceChart.resize();
usedmemory.resize();
usedmemory2.resize();
// trafficChart.resize(); // trafficChart.resize();
}); });
}, },
@ -841,14 +560,46 @@ mounted() {
this.historyQueryList.minTime = date[0] this.historyQueryList.minTime = date[0]
this.historyQueryList.maxTime = date[1] this.historyQueryList.maxTime = date[1]
this.gethistoryQuery(this.$route.params.id) this.gethistoryQuery(this.$route.params.id)
},
//
getTemperatureClass(temperature) {
if (!temperature || isNaN(temperature)) return 'temperature-normal';
const temp = Number(temperature);
if (temp < 20) return 'temperature-low';
if (temp >= 20 && temp <= 30) return 'temperature-normal';
if (temp > 30 && temp <= 40) return 'temperature-high';
return 'temperature-danger';
},
//
getHealthClass(health) {
switch(health) {
case 1:
return 'health-excellent';
case 2:
return 'health-good';
case 3:
return 'health-fair';
case 4:
return 'health-poor';
default:
return 'health-good';
}
},
// 使
getUtilizationClass(utilization) {
if (!utilization || isNaN(utilization)) return 'utilization-normal';
const value = Number(utilization);
if (value <= 50) return 'utilization-normal';
if (value > 50 && value <= 80) return 'utilization-warning';
return 'utilization-danger';
} }
} }
} }
</script> </script>
<style scoped> <style scoped>
.scroll-height-500 { .scroll-height-680 {
height: 500px; height: 680px;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
} }
@ -1138,4 +889,211 @@ mounted() {
font-weight: 600; font-weight: 600;
border-bottom: 2px solid #2d3748; border-bottom: 2px solid #2d3748;
} }
</style> .info-value {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: help;
}
</style>
<style scoped>
.health-indicators {
padding: 20px 20px 0;
background: #fff;
border-radius: 8px;
}
.section-title {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 20px;
}
.health-card {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 180px;
padding: 10px 0;
box-sizing: border-box;
background: linear-gradient(135deg, #edf2f7, #e2e8f0);
border-radius: 12px;
border: 1px solid rgba(226, 232, 240, 0.8);
transition: all 0.3s ease;
margin-bottom: 16px;
}
.health-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 10px;
width: 100%;
padding-left: 16px;
}
.health-card:hover {
background: rgba(255, 255, 255, 0.9);
border-color: rgba(66, 153, 225, 0.3);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.health-label {
font-size: 14px;
color: #2d3748;
margin-bottom: 0;
text-align: left;
font-weight: bold;
}
.health-icon {
position: relative;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
margin-bottom: 0;
background: #e6f7ff;
color: #1890ff;
}
.health-circle {
width: 120px;
height: 120px;
border-radius: 50%;
display: flex;
/* flex-direction: column; */
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
/* 圆形背景颜色 */
/* 温度相关样式 */
.health-circle.temperature-low {
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
}
.health-circle.temperature-normal {
background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
}
.health-circle.temperature-high {
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
}
.health-circle.temperature-danger {
background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
}
.health-value.temperature-low {
color: #0ea5e9;
}
.health-value.temperature-normal {
color: #22c55e;
}
.health-value.temperature-high {
color: #f59e0b;
}
.health-value.temperature-danger {
color: #ef4444;
}
/* 健康度相关样式 */
.health-circle.health-excellent {
background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
}
.health-circle.health-good {
background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
}
.health-circle.health-fair {
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
}
.health-circle.health-poor {
background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
}
.health-value.health-excellent {
color: #22c55e;
}
.health-value.health-good {
color: #3b82f6;
}
.health-value.health-fair {
color: #f59e0b;
}
.health-value.health-poor {
color: #ef4444;
}
/* 使用率相关样式 */
.health-circle.utilization-normal {
background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
}
.health-circle.utilization-warning {
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
}
.health-circle.utilization-danger {
background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
}
.health-value.utilization-normal {
color: #22c55e;
}
.health-value.utilization-warning {
color: #f59e0b;
}
.health-value.utilization-danger {
color: #ef4444;
}
/* 系统色系样式 */
.health-circle.system-color {
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
}
.health-value.system-color {
color: #0ea5e9;
}
/* 图标颜色 */
.health-icon.blood-pressure,
.health-icon.heart-rate,
.health-icon.breath {
background: linear-gradient(135deg, #22c55e 0%, #4ade80 100%);
color: white;
}
.health-icon.cardio,
.health-icon.heart-rate-variability {
background: linear-gradient(135deg, #f97316 0%, #fb923c 100%);
color: white;
}
.health-icon.blood-oxygen {
background: linear-gradient(135deg, #ef4444 0%, #f87171 100%);
color: white;
}
.health-icon.system-color {
background: linear-gradient(135deg, #0ea5e9 0%, #38bdf8 100%);
color: white;
}
/* 数值样式 */
.health-value {
font-size: 28px;
font-weight: bold;
margin-bottom: 5px;
}
/* 单位样式 */
.health-unit {
font-size: 14px;
color: #666;
}
</style>

@ -9,6 +9,12 @@
<el-form-item label="预警时间"> <el-form-item label="预警时间">
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd hh:mm:ss" type="datetimerange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker> <el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd hh:mm:ss" type="datetimerange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="设备编号" prop="equNumber">
<el-input v-model="queryParams.equNumber" placeholder="设备编号" clearable style="width: 240px" />
</el-form-item>
<el-form-item label="设备名称" prop="name">
<el-input v-model="queryParams.name" placeholder="设备名称" clearable style="width: 240px" />
</el-form-item>
<el-form-item label="预警等级" prop="level"> <el-form-item label="预警等级" prop="level">
<el-select v-model="queryParams.level" placeholder="预警等级" clearable style="width: 240px"> <el-select v-model="queryParams.level" placeholder="预警等级" clearable style="width: 240px">
<el-option v-for="dict in dict.type.warning_level" :key="dict.value" :label="dict.label" :value="dict.value" /> <el-option v-for="dict in dict.type.warning_level" :key="dict.value" :label="dict.label" :value="dict.value" />
@ -27,26 +33,26 @@
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<!-- <el-col :span="1.5"> <!-- <el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['inMonitoring:message:add']">新增</el-button> <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['inMonitoring:alertMessage:add']">新增</el-button>
</el-col> --> </el-col> -->
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['inMonitoring:message:remove']">删除</el-button> <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['inMonitoring:alertMessage:remove']">删除</el-button>
</el-col> </el-col>
<!-- <el-col :span="1.5"> <!-- <el-col :span="1.5">
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['inMonitoring:message:import']">导入</el-button> <el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['inMonitoring:alertMessage:import']">导入</el-button>
</el-col> --> </el-col> -->
</el-row> </el-row>
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange"> <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" /> <el-table-column type="selection" width="50" align="center" />
<el-table-column <el-table-column label="序号"
label="序号"
width="60" width="60"
type="index" type="index"
></el-table-column> ></el-table-column>
<el-table-column label="设备名称" align="center" key="name" prop="name" width="150" :show-overflow-tooltip="true" />
<el-table-column label="预警时间" align="center" key="occurTime" prop="occurTime" :show-overflow-tooltip="true" /> <el-table-column label="预警时间" align="center" key="occurTime" prop="occurTime" :show-overflow-tooltip="true" />
<el-table-column label="预警等级" align="center" key="level" prop="level" :show-overflow-tooltip="true" /> <el-table-column label="预警等级" align="center" key="level" prop="level" :show-overflow-tooltip="true" />
<el-table-column label="预警信息" align="center" key="message" prop="message" width="200" :show-overflow-tooltip="true"> <el-table-column label="预警信息" align="left" key="message" prop="message" width="200" :show-overflow-tooltip="true">
<template slot-scope="scope"> <template slot-scope="scope">
<span @click="showContentDialog('预警信息', scope.row.message)" class="clickable-cell">{{ scope.row.message || '--' }}</span> <span @click="showContentDialog('预警信息', scope.row.message)" class="clickable-cell">{{ scope.row.message || '--' }}</span>
</template> </template>
@ -66,7 +72,7 @@
<span>{{ parseTime(scope.row.handleTime) || '--' }}</span> <span>{{ parseTime(scope.row.handleTime) || '--' }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="解决方案" align="center" key="solution" prop="solution" :show-overflow-tooltip="true" > <el-table-column label="解决方案" align="left" key="solution" prop="solution" :show-overflow-tooltip="true" >
<template slot-scope="scope"> <template slot-scope="scope">
<span @click="showContentDialog('解决方案', scope.row.solution)" class="clickable-cell">{{ scope.row.solution || '--'}}</span> <span @click="showContentDialog('解决方案', scope.row.solution)" class="clickable-cell">{{ scope.row.solution || '--'}}</span>
</template> </template>
@ -74,9 +80,9 @@
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button size="mini" v-if="scope.row.status == 'UNHANDLED'" type="text" @click="handleUpdate(scope.row)" v-hasPermi="['inMonitoring:message:edit']">去处理</el-button> <el-button size="mini" v-if="scope.row.status == 'UNHANDLED'" type="text" @click="handleUpdate(scope.row)" v-hasPermi="['inMonitoring:alertMessage:edit']">去处理</el-button>
<el-button size="mini" type="text" @click="handleUpdate(scope.row)" v-if="scope.row.status == 'HANDLED'" v-hasPermi="['inMonitoring:message:edit']">编辑</el-button> <el-button size="mini" type="text" @click="handleUpdate(scope.row)" v-if="scope.row.status == 'HANDLED'" v-hasPermi="['inMonitoring:alertMessage:edit']">编辑</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['inMonitoring:message:remove']">删除</el-button> <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['inMonitoring:alertMessage:remove']">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>

@ -34,8 +34,8 @@
type="index" type="index"
></el-table-column> ></el-table-column>
<el-table-column label="名称" align="center" key="ruleName" prop="ruleName" width="120"/> <el-table-column label="名称" align="center" key="ruleName" prop="ruleName" width="120"/>
<el-table-column label="描述" align="center" key="description" prop="description" width="240" :show-overflow-tooltip="true" /> <el-table-column label="描述" align="left" key="description" prop="description" width="240" :show-overflow-tooltip="true" />
<el-table-column label="触发条件" align="center" key="alertTemplate" prop="alertTemplate" width="240" :show-overflow-tooltip="true" > <el-table-column label="触发条件" align="left" key="alertTemplate" prop="alertTemplate" width="240" :show-overflow-tooltip="true" >
<template slot-scope="scope"> <template slot-scope="scope">
<span v-if="scope.row.paramName">{{ findParamName(scope.row.paramName) }} {{ scope.row.operator }} {{ scope.row.compareValue }}</span> <span v-if="scope.row.paramName">{{ findParamName(scope.row.paramName) }} {{ scope.row.operator }} {{ scope.row.compareValue }}</span>
<span v-else></span> <span v-else></span>
@ -43,7 +43,7 @@
</el-table-column> </el-table-column>
<el-table-column label="预警级别" align="center" key="severity" prop="severity" width="120" /> <el-table-column label="预警级别" align="center" key="severity" prop="severity" width="120" />
<el-table-column label="预警方式" align="center" key="alertWay" prop="alertWay" width="120" :show-overflow-tooltip="true" /> <el-table-column label="预警方式" align="center" key="alertWay" prop="alertWay" width="120" :show-overflow-tooltip="true" />
<el-table-column label="预警邮箱" align="center" key="alertStation" prop="alertStation" width="200" :show-overflow-tooltip="true" /> <el-table-column label="预警邮箱" align="left" key="alertStation" prop="alertStation" width="200" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['inMonitoring:alertRule:edit']">修改</el-button> <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['inMonitoring:alertRule:edit']">修改</el-button>

@ -378,7 +378,7 @@ export default {
// //
setInterval(() => { setInterval(() => {
this.refreshDeviceStatus(); this.refreshDeviceStatus();
}, 60000); }, 600000);
}, },
activated() { activated() {
// //
@ -926,9 +926,11 @@ export default {
}, },
// //
jumpToDeviceFiles(floor) { jumpToDeviceFiles(floor) {
// ''
const floorNumber = Number(String(floor).replace('层', ''));
this.$router.push({ this.$router.push({
path: '/device/files', path: '/device/files',
query: { floor: floor } query: { floor: floorNumber }
}); });
}, },

@ -14,7 +14,7 @@
></el-table-column> ></el-table-column>
<el-table-column label="消息ID" align="center" key="id" prop="id" width="80" /> <el-table-column label="消息ID" align="center" key="id" prop="id" width="80" />
<el-table-column label="用户ID" align="center" key="userId" prop="userId" width="80" /> <el-table-column label="用户ID" align="center" key="userId" prop="userId" width="80" />
<el-table-column label="消息内容" align="center" key="content" prop="content" :show-overflow-tooltip="true"> <el-table-column label="消息内容" align="left" key="content" prop="content" :show-overflow-tooltip="true">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.row.content || '--' }}</span> <span>{{ scope.row.content || '--' }}</span>
</template> </template>
@ -26,7 +26,7 @@
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="标题" align="center" key="title" prop="title" :show-overflow-tooltip="true"> <el-table-column label="标题" align="left" key="title" prop="title" :show-overflow-tooltip="true">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.row.title || '--' }}</span> <span>{{ scope.row.title || '--' }}</span>
</template> </template>

Loading…
Cancel
Save