Merge remote-tracking branch 'origin/dev' into dev

dev
Newek 11 months ago
commit 3870d1c5f2
  1. 148
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/equManagement/EquBaseController.java
  2. 6
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/equManagement/EquManuController.java
  3. 21
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/equManagement/EquSupplierController.java
  4. 24
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/equManagement/ScheduleRulesController.java
  5. 36
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/exceptionController/AlertMessageController.java
  6. 7
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/exceptionController/AlertRuleController.java
  7. 41
      ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/exceptionController/equAssessment.java
  8. 4
      ALOps_sys_backend/alops-admin/src/main/resources/application-druid.yml
  9. 2
      ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/web/service/SysLoginService.java
  10. 2
      ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/web/service/SysRegisterService.java
  11. 12
      ALOps_sys_backend/alops-system/pom.xml
  12. 6
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/AlertMessage.java
  13. 1
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/AlertRule.java
  14. 51
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/EquBase.java
  15. 2
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/EquInterface.java
  16. 4
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/EquManu.java
  17. 2
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/EquRouting.java
  18. 8
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/EquSupplier.java
  19. 5
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/EquVeneer.java
  20. 27
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/AlertStatisticDto.java
  21. 112
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/EquBaseAddDto.java
  22. 11
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/EquBaseQueryDto.java
  23. 22
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/EquMonitorHomeDto.java
  24. 17
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/EquSupplierAddDto.java
  25. 13
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/EquSupplierUpdateDto.java
  26. 22
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/LevelCountDto.java
  27. 8
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/MonitorHistoryDto.java
  28. 29
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/MonitorLastDto.java
  29. 14
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/MonitorListDto.java
  30. 5
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/MonitorStatisticDto.java
  31. 17
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/TypeCountDto.java
  32. 48
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/dto/equipmentAssessmentDto.java
  33. 75
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/AlertRuleVo.java
  34. 45
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/equipmentAssessmentVo.java
  35. 37
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/homeEquAlertMessageVo.java
  36. 28
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/queryEquBaseVO.java
  37. 30
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/job/GatherJob.java
  38. 3
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/mapper/AlertMessageMapper.java
  39. 7
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/mapper/AlertRuleMapper.java
  40. 22
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/mapper/EquBaseMapper.java
  41. 2
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/mapper/ScheduleRulesMapper.java
  42. 3
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/IAlertMessageService.java
  43. 5
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/IAlertRuleService.java
  44. 11
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/IEquBaseService.java
  45. 12
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/IEquSupplierService.java
  46. 4
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/IScheduleRulesService.java
  47. 4
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertLaunchServiceImpl.java
  48. 25
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertMessageServiceImpl.java
  49. 19
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertRuleServiceImpl.java
  50. 154
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/EquBaseServiceImpl.java
  51. 6
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/EquManuServiceImpl.java
  52. 44
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/EquSupplierServiceImpl.java
  53. 6
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/EquTypeServiceImpl.java
  54. 133
      ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/ScheduleRulesServiceImpl.java
  55. 29
      ALOps_sys_backend/alops-system/src/main/resources/mapper/system/AlertMessageMapper.xml
  56. 55
      ALOps_sys_backend/alops-system/src/main/resources/mapper/system/AlertRuleMapper.xml
  57. 307
      ALOps_sys_backend/alops-system/src/main/resources/mapper/system/EquBaseMapper.xml
  58. 3
      ALOps_sys_backend/alops-system/src/main/resources/mapper/system/EquManuMapper.xml
  59. 29
      ALOps_sys_backend/alops-system/src/main/resources/mapper/system/EquSupplierMapper.xml
  60. 1
      ALOps_sys_backend/alops-system/src/main/resources/mapper/system/EquTypeMapper.xml
  61. 2
      ALOps_sys_backend/alops-system/src/main/resources/mapper/system/EquVlanMapper.xml
  62. 6
      ALOps_sys_backend/alops-system/src/main/resources/mapper/system/ScheduleRulesMapper.xml
  63. 1
      ALOps_sys_fe/alops-ui/public/index.html
  64. 58
      ALOps_sys_fe/alops-ui/src/api/QandA/Aiassistant.js
  65. 52
      ALOps_sys_fe/alops-ui/src/api/QandA/dict/data.js
  66. 60
      ALOps_sys_fe/alops-ui/src/api/QandA/dict/type.js
  67. 49
      ALOps_sys_fe/alops-ui/src/api/QandA/knowledge.js
  68. 30
      ALOps_sys_fe/alops-ui/src/api/device/deviceInformation.js
  69. 7
      ALOps_sys_fe/alops-ui/src/api/device/deviceManufacturer.js
  70. 7
      ALOps_sys_fe/alops-ui/src/api/device/deviceType.js
  71. 4
      ALOps_sys_fe/alops-ui/src/api/device/files.js
  72. 49
      ALOps_sys_fe/alops-ui/src/api/device/supplier.js
  73. 50
      ALOps_sys_fe/alops-ui/src/api/inMonitoring/devicesState.js
  74. 58
      ALOps_sys_fe/alops-ui/src/api/inMonitoring/message.js
  75. 58
      ALOps_sys_fe/alops-ui/src/api/inMonitoring/rules.js
  76. 92
      ALOps_sys_fe/alops-ui/src/api/index/index.js
  77. BIN
      ALOps_sys_fe/alops-ui/src/assets/images/profile.jpg
  78. 17
      ALOps_sys_fe/alops-ui/src/components/ImageUpload/index.vue
  79. 2
      ALOps_sys_fe/alops-ui/src/router/index.js
  80. 1
      ALOps_sys_fe/alops-ui/src/utils/request.js
  81. 8
      ALOps_sys_fe/alops-ui/src/utils/ruoyi.js
  82. 4
      ALOps_sys_fe/alops-ui/src/views/QandA/Aiassistant/index.vue
  83. 352
      ALOps_sys_fe/alops-ui/src/views/QandA/knowledge/index.vue
  84. 372
      ALOps_sys_fe/alops-ui/src/views/device/deviceInformation/index.vue
  85. 136
      ALOps_sys_fe/alops-ui/src/views/device/deviceManufacturer/index.vue
  86. 4
      ALOps_sys_fe/alops-ui/src/views/device/deviceSupplier/index.vue
  87. 236
      ALOps_sys_fe/alops-ui/src/views/device/deviceType/index.vue
  88. 315
      ALOps_sys_fe/alops-ui/src/views/device/files/index.vue
  89. 348
      ALOps_sys_fe/alops-ui/src/views/device/supplier/index.vue
  90. 4
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/assessment/index.vue
  91. 514
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/devicesState/cardItem.vue
  92. 839
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/devicesState/detail.vue
  93. 69
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/devicesState/history.vue
  94. 36
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/devicesState/index.vue
  95. 509
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/earlyWarning/index.vue
  96. 321
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/inMonitor/message/index.vue
  97. 445
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/inMonitor/rules/index.vue
  98. 308
      ALOps_sys_fe/alops-ui/src/views/index copy.vue
  99. 818
      ALOps_sys_fe/alops-ui/src/views/index.vue
  100. 185
      ALOps_sys_fe/alops-ui/src/views/index2.vue
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,7 +1,9 @@
package com.alops.web.controller.equManagement;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
@ -14,6 +16,7 @@ import com.alops.common.enums.BusinessType;
import com.alops.common.utils.poi.ExcelUtil;
import com.alops.system.domain.EquBase;
import com.alops.system.domain.dto.EquBaseQueryDto;
import com.alops.system.domain.dto.EquMonitorHomeDto;
import com.alops.system.domain.dto.MonitorListDto;
import com.alops.system.domain.dto.MonitorStatisticDto;
import com.alops.system.domain.vo.EquMonitorVO;
@ -48,9 +51,9 @@ public class EquBaseController extends BaseController
* 查询设备基本信息列表
*/
@PreAuthorize("@ss.hasPermi('device:files:list')")
@PostMapping("/list")
@GetMapping("/list")
@ApiOperation("查询多个设备信息")
public TableDataInfo list(@RequestBody EquBaseQueryDto equBase)
public TableDataInfo list( EquBaseQueryDto equBase)
{
startPage();
List<queryEquBaseVO> list = equBaseService.selectEquBaseList(equBase);
@ -58,15 +61,31 @@ public class EquBaseController extends BaseController
}
/**查询设备监测信息列表(查询多台显示界面的单独信息)**/
/**
* 查询多台设备的最新监测信息
**/
@PreAuthorize("@ss.hasPermi('device:files:query')")
@GetMapping("/listMonitor")
@ApiOperation("查询设备监测信息列表(查询多台显示界面的单独信息)")
public AjaxResult listMonitorInfo(EquBaseQueryDto equBaseQueryDto)
{
List<MonitorListDto> list = equBaseService.selectEquMonitorList(equBaseQueryDto);
return AjaxResult.success("查询成功", list);
@GetMapping("/monitorpage")
@ApiOperation("分页查询多台设备的最新监测信息")
public TableDataInfo getMonitorList() {
startPage(); // 无参调用,自动获取 pageNum/pageSize
List<MonitorListDto> list = equBaseService.selectEquMonitorListPaged();
return getDataTable(list); // 自动封装分页结果
}
/**
* 首页展示查询每台设备的最新监测信息
*/
@PreAuthorize("@ss.hasPermi('device:files:query')")
@GetMapping("/monitorById")
@ApiOperation("首页展示:查询每台设备的最新监测信息")
public TableDataInfo getLatestEquMonitorList() {
startPage(); // 启用分页(如果首页不分页可删除)
List<EquMonitorHomeDto> list = equBaseService.selectLatestEquMonitorList();
return getDataTable(list);
}
/**
* 获取设备最新时间的历史监控信息
* @param id 查询对象包含设备ID开始时间和结束时间
@ -80,6 +99,7 @@ public class EquBaseController extends BaseController
// 调用职责单一的 Service 方法
return success(equBaseService.selectLatestEquMonitorInfo(id));
}
/**
* 获取设备指定时间段内的历史监控信息
* @param equBaseQueryDto 查询对象包含设备ID开始时间和结束时间
@ -101,9 +121,18 @@ public class EquBaseController extends BaseController
@ApiOperation("按设备类型分类统计设备信息")
public AjaxResult listMonitorInfoByType() {
List<MonitorStatisticDto> list = equBaseService.selectEquStatisticByType();
return AjaxResult.success("查询成功", list);
// 获取总设备数
int totalCount = 0;
if (list != null) {
totalCount = list.stream().mapToInt(MonitorStatisticDto::getCount).sum();
}
Map<String, Object> result = new HashMap<>();
result.put("totalCount", totalCount);
result.put("list", list);
return AjaxResult.success("查询成功", result);
}
/**
* 获取设备基本信息详细信息
*/
@ -116,38 +145,35 @@ public class EquBaseController extends BaseController
}
/**
* 根据设备ID返回图片流
* 前端直接 <img src="/equBase/image/{id}">
*/
@PreAuthorize("@ss.hasPermi('device:files:queryimage')")
@GetMapping(value = "/queryimage/{id}")
@ApiOperation("查询单个设备图片")
public void getImage(@PathVariable String id, HttpServletResponse response) throws IOException {
if (id instanceof String) {
System.out.println("这是一个字符串");
}
byte[] imgBytes = equBaseService.selectEquBaseImageById(id).getEquImage();
// /**
// * 根据设备ID返回图片流
// * 前端直接 <img src="/equBase/image/{id}">
// */
//
// @PreAuthorize("@ss.hasPermi('device:files:queryimage')")
// @GetMapping(value = "/queryimage/{id}")
// @ApiOperation("查询单个设备图片")
// public void getImage(@PathVariable String id, HttpServletResponse response) throws IOException {
//
// byte[] imgBytes = equBaseService.selectEquBaseImageById(id).getEquImage();
//
//
// if (imgBytes != null && imgBytes.length > 0) {
// // 设置响应类型,可根据实际图片类型动态修改
// response.setContentType("image/png");
// // 可选:缓存图片
// response.setHeader("Cache-Control", "max-age=3600");
// // 输出流写入响应
// ServletOutputStream os = response.getOutputStream();
// os.write(imgBytes);
// os.flush();
// os.close();
// } else {
// // 图片不存在
// response.sendError(HttpServletResponse.SC_NOT_FOUND);
// }
// }
if (imgBytes != null && imgBytes.length > 0) {
// 设置响应类型,可根据实际图片类型动态修改
response.setContentType("image/png");
// 可选:缓存图片
response.setHeader("Cache-Control", "max-age=3600");
// 输出流写入响应
ServletOutputStream os = response.getOutputStream();
os.write(imgBytes);
os.flush();
os.close();
} else {
// 图片不存在
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
//厂商下拉表
@PreAuthorize("@ss.hasPermi('device:files:queryManufacture')")
@GetMapping( "/manufacture")
@ -181,46 +207,44 @@ public class EquBaseController extends BaseController
/**
* 新增设备基本信息
* @ModelAttribute equBase
* @RequestPart(value = "file", required = false) // 使用 @RequestPart
* @ApiParam(value = "设备图片文件", type = "file")
* MultipartFile file
*/
@PreAuthorize("@ss.hasPermi('device:files:add')")
@Log(title = "设备基本信息", businessType = BusinessType.INSERT)
@PostMapping(value = "/add")
@ApiOperation("增加设备档案信息")
public AjaxResult add(
@ModelAttribute EquBase equBase,
@RequestPart(value = "file", required = false) // 使用 @RequestPart
@ApiParam(value = "设备图片文件", type = "file")
MultipartFile file
) throws IOException {
public AjaxResult add( @RequestBody EquBase equBase
) {
// 处理图片
if (file != null && !file.isEmpty()) {
equBase.setEquImage(file.getBytes());
}
// // 处理图片
// if (file != null && !file.isEmpty()) {
// equBase.setEquImage(file.getBytes());
// }
// 调用 Service 插入数据库
return toAjax(equBaseService.insertEquBase(equBase));
}
/**
* @ModelAttribute EquBase equBase, // 自动绑定表单字段
* @RequestPart(value = "file", required = false) // 使用 @RequestPart
* @ApiParam(value = "设备图片文件", type = "file")
* MultipartFile file
* 修改设备基本信息
*/
@PreAuthorize("@ss.hasPermi('device:files:edit')")
@Log(title = "设备基本信息", businessType = BusinessType.UPDATE)
@PutMapping("/modify")
@ApiOperation("修改设备档案信息")
public AjaxResult edit(
@ModelAttribute EquBase equBase, // 自动绑定表单字段
@RequestPart(value = "file", required = false) // 使用 @RequestPart
@ApiParam(value = "设备图片文件", type = "file")
MultipartFile file
) throws IOException {
// 处理图片
if (file != null && !file.isEmpty()) {
equBase.setEquImage(file.getBytes()); // 存数据库 Blob
}
public AjaxResult edit(@RequestBody EquBase equBase){
// // 处理图片
// if (file != null && !file.isEmpty()) {
// equBase.setEquImage(file.getBytes()); // 存数据库 Blob
// }
// 调用 Service 插入数据库
return toAjax(equBaseService.updateEquBase(equBase));

@ -33,7 +33,7 @@ import org.springframework.web.bind.annotation.RestController;
* @date 2025-08-01
*/
@RestController
@RequestMapping("/deviceManu")
@RequestMapping("/device/deviceManu")
public class EquManuController extends BaseController
{
@Autowired
@ -42,8 +42,8 @@ public class EquManuController extends BaseController
/**
* 查询设备厂商管理列表
*/
@PreAuthorize("@ss.hasPermi('device:deviceManu:queryByVO')")
@GetMapping("/queryByVO")
@PreAuthorize("@ss.hasPermi('device:deviceManu:query')")
@GetMapping("/query")
@ApiOperation("查询设备厂商管理列表")
public TableDataInfo list(EquManu equManu)
{

@ -1,8 +1,11 @@
package com.alops.web.controller.equManagement;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletResponse;
import com.alops.system.domain.dto.EquSupplierAddDto;
import com.alops.system.domain.dto.EquSupplierUpdateDto;
import io.swagger.annotations.ApiOperation;
import com.alops.common.annotation.Log;
import com.alops.common.core.controller.BaseController;
@ -85,25 +88,27 @@ public class EquSupplierController extends BaseController
*/
@PreAuthorize("@ss.hasPermi('device:supplier:add')")
@Log(title = "供应商功能信息", businessType = BusinessType.INSERT)
@PostMapping
@ApiOperation("新增供应商功能信息列表")
public AjaxResult add(@RequestBody EquSupplier equSupplier)
@PostMapping("/add")
@ApiOperation("新增供应商功能信息")
public AjaxResult add(@RequestBody EquSupplierAddDto dto)
{
return toAjax(equSupplierService.insertEquSupplier(equSupplier));
return toAjax(equSupplierService.insertEquSupplier(dto));
}
/**
* 修改供应商功能信息
*/
@PreAuthorize("@ss.hasPermi('device:supplier:edit')")
@Log(title = "供应商功能信息", businessType = BusinessType.UPDATE)
@PutMapping
@PutMapping("/edit")
@ApiOperation("修改供应商功能信息列表")
public AjaxResult edit(@RequestBody EquSupplier equSupplier)
{
return toAjax(equSupplierService.updateEquSupplier(equSupplier));
public AjaxResult edit(@RequestBody EquSupplierUpdateDto updateDto) {
return toAjax(equSupplierService.updateEquSupplier(updateDto));
}
/**
* 删除供应商功能信息
*/

@ -58,25 +58,29 @@ public class ScheduleRulesController extends BaseController
@PreAuthorize("@ss.hasPermi('device:deviceInformation:protoCollect')")
@PostMapping("/addRule")
@ApiOperation("立即确定")
public AjaxResult run(@RequestBody ScheduleRules newRule) throws SchedulerException, ExecutionException, InterruptedException {
if (newRule.getRuleType() == 2) {
// 立即执行
return scheduleRulesService.executeRule(newRule);
public AjaxResult run(@RequestBody ScheduleRules newRule) throws SchedulerException, ExecutionException, InterruptedException {
} else {
// 固定时间/按频率:异步处理异常
scheduleRulesService.executeRule(newRule);
// 先检查是否有任务正在执行
if (scheduleRulesService.checkRunningOrWaitingRules()) {
return AjaxResult.error(4001,"正在采集,请稍后,此次采集完成后会站内信通知到你");
}
return AjaxResult.success("任务已调度成功,异常会通过站内信/邮件通知");
}
// 执行规则(立即或定时/按频率)
boolean success = scheduleRulesService.executeRule(newRule);
if (success) {
// 返回调度/插入成功
return AjaxResult.success("任务已调度成功,采集结果会通过站内信/邮件通知");
} else {
return AjaxResult.error("任务设置失败,请稍后重试");
}
}
/**
* 查询定时采集规则列表
*/

@ -1,34 +1,22 @@
package com.alops.web.controller.exceptionController;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import com.alops.common.annotation.Log;
import com.alops.common.core.controller.BaseController;
import com.alops.common.core.domain.AjaxResult;
import com.alops.common.core.page.TableDataInfo;
import com.alops.common.enums.BusinessType;
import com.alops.common.utils.SecurityUtils;
import com.alops.common.utils.poi.ExcelUtil;
import com.alops.system.domain.AlertMessage;
import com.alops.system.domain.dto.AlertDto;
import com.alops.system.domain.vo.homeEquAlertMessageVo;
import com.alops.system.service.IAlertLaunchService;
import com.alops.system.domain.AlertRule;
import com.alops.system.domain.EquInterface;
import com.alops.system.domain.dto.AlertStatisticDto;
import com.alops.system.service.IAlertMessageService;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
/**
* 故障统计Controller
@ -91,12 +79,26 @@ public class AlertMessageController extends BaseController
/**
* 查询预警信息统计列表
*/
@PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:list')")
@PostMapping ("/list")
@PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:statistic:list')")
@GetMapping ("/statistic/list")
@ApiOperation("查询预警信息")
@Log(title = "查询预警信息", businessType = BusinessType.UPDATE)
public TableDataInfo homeList()
{
startPage();
List<homeEquAlertMessageVo> list = alertMessageService.selectStaticAlertMessageList();
return getDataTable(list);
}
public TableDataInfo list( @RequestBody AlertDto alertMessage)
/**
* 首页查询预警信息统计列表
*/
@PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:list')")
@GetMapping ("/list")
@ApiOperation("查询预警信息")
@Log(title = "查询预警信息", businessType = BusinessType.UPDATE)
public TableDataInfo list( AlertDto alertMessage)
{
startPage();
List<AlertMessage> list = alertMessageService.selectAlertMessageList(alertMessage);

@ -12,6 +12,7 @@ import com.alops.common.enums.BusinessType;
import com.alops.common.utils.poi.ExcelUtil;
import com.alops.system.domain.AlertRule;
import com.alops.system.domain.dto.AlertRuleAddDto;
import com.alops.system.domain.vo.AlertRuleVo;
import com.alops.system.service.IAlertLaunchService;
import com.alops.system.service.IAlertRuleService;
import com.alops.system.service.IDictAlarmParamService;
@ -55,7 +56,7 @@ public class AlertRuleController extends BaseController {
try {
AlertRule alertRule = alertRuleService.saveRule(dto);
AlertRuleVo alertRule = alertRuleService.saveRule(dto);
return AjaxResult.success("预警规则新增成功", alertRule);
} catch (Exception e) {
e.printStackTrace();
@ -69,7 +70,7 @@ public class AlertRuleController extends BaseController {
@PreAuthorize("@ss.hasPermi('inMonitoring:alertRule:edit')")
@ApiOperation("修改预警规则")
@Log(title = "【修改预警规则】", businessType = BusinessType.DELETE)
@PostMapping("/editRule")
@PutMapping("/editRule")
public AjaxResult editRule(@RequestBody AlertRuleAddDto dto) {
try {
AlertRule alertRule = alertRuleService.updateRule(dto);
@ -89,7 +90,7 @@ public class AlertRuleController extends BaseController {
@ApiOperation("查询预警规则")
public TableDataInfo list(AlertRule alertRule) {
startPage();
List<AlertRule> list = alertRuleService.selectAlertRuleList(alertRule);
List<AlertRuleVo> list = alertRuleService.selectAlertRuleList(alertRule);
return getDataTable(list);
}

@ -0,0 +1,41 @@
package com.alops.web.controller.exceptionController;
import com.alops.common.annotation.Log;
import com.alops.common.core.controller.BaseController;
import com.alops.common.core.page.TableDataInfo;
import com.alops.common.enums.BusinessType;
import com.alops.system.domain.vo.equipmentAssessmentVo;
import com.alops.system.service.IEquBaseService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/inMonitoring/equAssessment")
public class equAssessment extends BaseController {
@Autowired
public IEquBaseService iEquBaseService;
/**
* 设备信息评估表
* 获取所有设备id
*/
@PreAuthorize("@ss.hasPermi('inMonitoring:equAssessment:list')")
@GetMapping("/list")
@ApiOperation("设备评估信息")
@Log(title = "设备评估与预测", businessType = BusinessType.UPDATE)
public TableDataInfo homeList()
{
startPage();
List<equipmentAssessmentVo> list = iEquBaseService.getDeviceIAssessmentnfo();
return getDataTable(list);
}
}

@ -6,8 +6,8 @@ spring:
druid:
# 主库数据源
master:
url: jdbc:mysql://localhost:3306/AIOps_sys?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
url: jdbc:mysql://localhost:3306/aiops_sys?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: aiops_sys
password: 1234
# 从库数据源
slave:

@ -29,6 +29,8 @@ import com.alops.framework.security.context.AuthenticationContextHolder;
import com.alops.system.service.ISysConfigService;
import com.alops.system.service.ISysUserService;
import java.util.Date;
/**
* 登录校验方法
*

@ -19,6 +19,8 @@ import com.alops.framework.manager.factory.AsyncFactory;
import com.alops.system.service.ISysConfigService;
import com.alops.system.service.ISysUserService;
import java.util.Date;
/**
* 注册校验方法
*

@ -16,6 +16,18 @@
<description>
system系统模块
</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>14</source>
<target>14</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- org.snmp4j -->

@ -9,6 +9,8 @@ import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.mail.Message;
/**
* 故障统计对象 alert_message
*
@ -23,7 +25,6 @@ public class AlertMessage
/** ID */
private Long id;
/** 设备ID */
@Excel(name = "设备ID")
private String equId;
@ -70,6 +71,9 @@ public class AlertMessage
@Excel(name = "信息批次")
private Integer batch;
@Excel(name ="预警信息")
private String message;

@ -62,6 +62,7 @@ public class AlertRule extends BaseEntity
public void setId(Long id)
{
this.id = id;

@ -15,7 +15,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
* 设备基本信息对象 equ_base
*
* @author ruoyi
* @date 2025-09-19
* @date 2025-09-19F
*/
@Data
public class EquBase
@ -25,6 +25,9 @@ public class EquBase
/** 设备唯一标识(设备编号) */
private String id;
/** (设备编号) */
private String equNumber;
/** 设备名称 */
@Excel(name = "设备名称")
private String name;
@ -39,15 +42,8 @@ public class EquBase
/** 设备厂商 id */
@Excel(name = "设备厂商 id")
private String manufacture;
private String equManuId;
public EquManu getManufactureVO() {
return manufactureVO;
}
public void setManufactureVO(EquManu manufactureVO) {
this.manufactureVO = manufactureVO;
}
private EquManu manufactureVO;
@ -57,7 +53,9 @@ public class EquBase
/** 设备类型 id */
@Excel(name = "设备类型 id")
private String equType;
private String equTypeId;
public EquType getEquTypeVO() {
return equTypeVO;
@ -118,8 +116,8 @@ public class EquBase
@Excel(name = "采集次数")
private Long createBy ;
@Excel(name = "设备图片")
private byte[] equImage ;
@Excel(name = "设备图片地址")
private String equImage ;
public void setId(String id)
@ -162,16 +160,6 @@ public class EquBase
return ip;
}
public void setManufacture(String manufacture)
{
this.manufacture = manufacture;
}
public String getManufacture()
{
return manufacture;
}
public void setLocation(String location)
{
this.location = location;
@ -182,16 +170,6 @@ public class EquBase
return location;
}
public void setEquType(String equType)
{
this.equType = equType;
}
public String getEquType()
{
return equType;
}
public void setInCharge(String inCharge)
{
this.inCharge = inCharge;
@ -292,6 +270,11 @@ public class EquBase
return gatherFrequency;
}
public String getEquManuId() { return equManuId; }
public void setEquManuId(String equManuId) { this.equManuId = equManuId; }
public String getEquTypeId() { return equTypeId; }
public void setEquTypeId(String equTypeId) { this.equTypeId = equTypeId; }
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@ -299,9 +282,9 @@ public class EquBase
.append("name", getName())
.append("version", getVersion())
.append("ip", getIp())
.append("manufacture", getManufacture())
.append("equManuId", getEquManuId())
.append("location", getLocation())
.append("equType", getEquType())
.append("equTypeId", getEquTypeId())
.append("inCharge", getInCharge())
.append("installDate", getInstallDate())
.append("lifeCycle", getLifeCycle())

@ -17,7 +17,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
* @date 2025-08-20
*/
@Data
public class EquInterface extends BaseEntity
public class EquInterface
{
private static final long serialVersionUID = 1L;

@ -31,8 +31,8 @@ public class EquManu
@Excel(name = "厂商简介")
private String description;
/** 联系人ID */
@Excel(name = "联系人ID")
/** 联系人*/
@Excel(name = "联系人")
private String contactBy;
/** 联系方式 */

@ -14,7 +14,7 @@ import org.apache.ibatis.annotations.Mapper;
* @date 2025-08-15
*/
@Data
public class EquRouting extends BaseEntity
public class EquRouting
{
private static final long serialVersionUID = 1L;

@ -41,8 +41,8 @@ public class EquSupplier
@Excel(name = "l联系方式")
private String contactWay;
/** 联系人姓名 */
@Excel(name = "创建人id")
private long createBy;
@Excel(name = "创建人")
private String createBy;
@ -117,12 +117,12 @@ public class EquSupplier
return status;
}
public Long getCreateBy()
public String getCreateBy()
{
return createBy;
}
public void setCreateBy(Long createBy)
public void setCreateBy(String createBy)
{
this.createBy = createBy;
}

@ -14,7 +14,7 @@ import org.apache.ibatis.annotations.Mapper;
* @date 2025-08-15
*/
@Data
public class EquVeneer extends BaseEntity
public class EquVeneer
{
private static final long serialVersionUID = 1L;
@ -34,8 +34,7 @@ public class EquVeneer extends BaseEntity
@Excel(name = "采集id")
private String equGatherId;
@Excel(name = "采集+预警同一批标志")
private String batchId;
public void setId(String id)
{

@ -1,6 +1,9 @@
package com.alops.system.domain.dto;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
@ -8,15 +11,23 @@ import java.util.Map;
*/
@Data
public class AlertStatisticDto {
// 按设备类型统计
private Map<String, Integer> typeCount;
// 按等级统计
private Map<Integer, Integer> levelCount;
// 本年度预警次数
private List<TypeCountDto> typeCount = new ArrayList<>();
private List<LevelCountDto> levelCount = new ArrayList<>();
private Integer yearCount;
// 本月预警次数
private Integer monthCount;
public List<TypeCountDto> getTypeCount() { return typeCount; }
public void setTypeCount(List<TypeCountDto> typeCount) { this.typeCount = typeCount; }
public List<LevelCountDto> getLevelCount() { return levelCount; }
public void setLevelCount(List<LevelCountDto> levelCount) { this.levelCount = levelCount; }
public Integer getYearCount() { return yearCount; }
public void setYearCount(Integer yearCount) { this.yearCount = yearCount; }
public Integer getMonthCount() { return monthCount; }
public void setMonthCount(Integer monthCount) { this.monthCount = monthCount; }
}

@ -0,0 +1,112 @@
package com.alops.system.domain.dto;
import com.alops.common.annotation.Excel;
import com.alops.system.domain.EquManu;
import com.alops.system.domain.EquType;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class EquBaseAddDto {
private static final long serialVersionUID = 1L;
/** 设备唯一标识(设备编号) */
private String id;
/** (设备编号) */
private String equNumber;
/** 设备名称 */
@Excel(name = "设备名称")
private String name;
/** 设备版本 */
@Excel(name = "设备版本")
private String version;
/** 带外管理 IP */
@Excel(name = "带外管理 IP")
private String ip;
/** 设备厂商 id */
@Excel(name = "设备厂商 id")
private String manufacture;
private EquManu manufactureVO;
/** 安装位置 */
@Excel(name = "安装位置 ")
private String location;
/** 设备类型 id */
@Excel(name = "设备类型 id")
private String equType;
public EquType getEquTypeVO() {
return equTypeVO;
}
public void setEquTypeVO(EquType equTypeVO) {
this.equTypeVO = equTypeVO;
}
private EquType equTypeVO;
/** 设备管理员姓名 */
@Excel(name = "设备管理员姓名")
private String inCharge;
/** 安装日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "安装日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date installDate;
/** 预计年限(年) */
@Excel(name = "预计年限(年)")
private Long lifeCycle;
/** 质保时间(年) */
@Excel(name = "质保时间(年)")
private Long warranty;
/** 添加日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "添加日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date createDate;
/** 启用状态(1启用0禁用) */
@Excel(name = "启用状态", readConverterExp = "0=启用1禁用")
private Long status;
/** 累计预警次数 */
@Excel(name = "累计预警次数")
private Long failureFrequency;
/** 设备级别 */
@Excel(name = "设备级别")
private String deviceLevel;
/** 供应商id */
@Excel(name = "供应商id")
private String supplierId;
/** 采集次数 */
@Excel(name = "采集次数")
private Long gatherFrequency;
@Excel(name = "采集次数")
private Long createBy ;
@Excel(name = "设备图片地址")
private String equImage ;
}

@ -16,18 +16,17 @@ public class EquBaseQueryDto implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
/** 设备类型 (equ_type, varchar) */
private String equTypeId;
/** 设备类型 (equ_type, varchar) */
private String equTypeId;
/** 设备类型 (equ_type, varchar) */
private String equType;
/** 设备名称 (name, varchar) */
private String name;
/** 安装位置 ID (location, varchar) */
private String location;
/** 起始时间 (min_time) */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date minTime;
@ -40,8 +39,6 @@ public class EquBaseQueryDto implements Serializable {
private Integer status;
// ====== Getter 和 Setter ======
public String getName() {
return name;
}

@ -0,0 +1,22 @@
package com.alops.system.domain.dto;
import lombok.Data;
import java.util.Date;
/**
* 首页展示设备监测简要信息
*/
@Data
public class EquMonitorHomeDto {
private String id;
private String equNumber; //设备编号
private String name; // 设备名称
private String location; // 设备位置
private Float cpuUtilization; // CPU 使用率
private Float memoryUtilization; // 内存使用率
private Float temperature; // 温度
private String health; // 健康度
private String contWorkPeriod; // 持续运行时长
private Date gatherTime; // 采集时间
}

@ -0,0 +1,17 @@
package com.alops.system.domain.dto;
import lombok.Data;
/**
* 新增供应商 DTO
* 只包含前端可传的字段
*/
@Data
public class EquSupplierAddDto {
private String name;
private String description;
private String contactBy;
private String contactWay;
private Long status;
}

@ -0,0 +1,13 @@
package com.alops.system.domain.dto;
import lombok.Data;
@Data
public class EquSupplierUpdateDto {
private String contactBy;
private String contactWay;
private String description;
private String id;
private String name;
private Long status;
}

@ -0,0 +1,22 @@
package com.alops.system.domain.dto;
public class LevelCountDto {
private String level;
private Integer count;
// 无参构造器
public LevelCountDto() {}
// 带参构造器
public LevelCountDto(String level, Integer count) {
this.level = level;
this.count = count;
}
// getter & setter
public String getLevel() { return level; }
public void setLevel(String level) { this.level = level; }
public Integer getCount() { return count; }
public void setCount(Integer count) { this.count = count; }
}

@ -7,9 +7,9 @@ import java.util.List;
public class MonitorHistoryDto {
// 返回给前端的字段
private List<Float> temperatureList = new ArrayList<>();
private List<Float> involtageList = new ArrayList<>();
private List<Float> outvoltageList = new ArrayList<>();
private List<Float> memoryList = new ArrayList<>();
private List<Float> cpuList = new ArrayList<>();
private List<Float> healthList = new ArrayList<>();
private List<String> timeList = new ArrayList<>();
}

@ -1,19 +1,25 @@
package com.alops.system.domain.dto;
import lombok.Data;
import java.sql.Blob;
import java.util.Date;
@Data
public class MonitorLastDto {
// equ_gather 表
private Integer contWorkPeriod;
private String contWorkPeriod;
private Float fanSpeed;
private Float cpuUtilization;
private Float memoryUtilization;
private String health;
private String volIn;
private String volOut;
private String temperature;
// equ_base 表
private Long id;
private String id;
private String equNumber;
private String name;
private String version;
private String deviceLevel;
@ -21,17 +27,24 @@ public class MonitorLastDto {
private String location;
private Date installDate;
private String inCharge;
private Integer failureFrequency;
private Integer warranty;
private String status;
private int warranty;
private String equImage;
// equ_type
private String equType;
private String equTypeId;
private String equTypeName;
// equ_manu
private String manufacture;
private String manufactureContactBy;
private String manufactureContactWay;
private String equManuId;
private String equManuName;
private String ContactBy;
private String ContactWay;
// equ_supplier
private String supplierId;
private String supplierName;
private int AlertCount;
private String unhandledAlertCount;
}

@ -11,15 +11,23 @@ import java.sql.Blob;
public class MonitorListDto {
private String id;
private String name;
private String ip;
private String equTypeId;
private String equTypeName;
private String equManuId;
private String equManuName;
private String version;
private String deviceLevel;
private String location;
private String status;
private Integer failureFrequency;
private Blob equImage;
// 监控指标
private Float cpuUtilization;
private String health;
private Integer fanSpeed;
private int fanSpeed;
private String contWorkPeriod;
private int AlertCount;;
private int unhandledAlertCount;
}

@ -11,6 +11,11 @@ public class MonitorStatisticDto {
private String equTypeName; // 设备类型名称
private List<DeviceSimpleInfo> devices; // 属于该类型的设备列表
// 新增统计数量字段
private Integer count;
// 每类型占总设备数量的百分比
private Double percentage;
@Data
public static class DeviceSimpleInfo {
private String id;

@ -0,0 +1,17 @@
package com.alops.system.domain.dto;
public class TypeCountDto {
private String name;
private Integer count;
public TypeCountDto() {}
public TypeCountDto(String name, Integer count) {
this.name = name;
this.count = count;
}
// getter/setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getCount() { return count; }
public void setCount(Integer count) { this.count = count; }
}

@ -0,0 +1,48 @@
package com.alops.system.domain.dto;
import com.alops.common.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class equipmentAssessmentDto {
/** 设备唯一标识(设备编号) */
private String id;
/** (设备编号) */
private String equNumber;
/** 设备名称 */
@Excel(name = "设备名称")
private String name;
/** 安装位置 */
@Excel(name = "安装位置 ")
private String location;
/** 设备类型 id */
@Excel(name = "设备类型名称")
private String equType;
/** 设备级别 */
@Excel(name = "设备级别")
private String deviceLevel;
@Excel(name = "综合计算的健康度指标(%)")
private BigDecimal health;
/** 设备温度 */
@Excel(name = "设备温度")
private BigDecimal temperature;
/** CPU 使用率(%) */
@Excel(name = "CPU 使用率(%)")
private BigDecimal cpuUtilization;
/** 内存使用率(%) */
@Excel(name = "内存使用率(%)")
private BigDecimal memoryUtilization;
}

@ -0,0 +1,75 @@
package com.alops.system.domain.vo;
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 java.util.Date;
@Data
public class AlertRuleVo extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 主键 */
private Long id;
/** 预警规则名称 */
@Excel(name = "预警规则名称")
private String ruleName;
/** 预警级别 */
@Excel(name = "预警级别")
private Long severity;
/** 预警方式(email/message) */
@Excel(name = "预警方式(email/message)")
private String alertWay;
/** 预警到站方 */
@Excel(name = "预警到站方")
private String alertStation;
/** 预警规则内容描述 */
@Excel(name = "预警规则内容描述")
private String description;
/** 启用状态(0为启用) */
@Excel(name = "启用状态", readConverterExp = "0=为启用")
private Integer enable;
/** 表格名称 */
@Excel(name = "表格名称")
private String tableName;
/** 预警sql语句查询 */
@Excel(name = "预警sql语句查询")
@JsonIgnore
private String alertSql;
/** 预警模版(参数用数据库命名法) */
@Excel(name = "预警模版", readConverterExp = "参=数用数据库命名法")
private String alertTemplate;
/** 预警类型 */
@Excel(name = "预警类型")
private String type;
/** 参数名称 */
@Excel(name = "参数名称")
private String paramName;
/** 比较符号 */
@Excel(name = "比较符号")
private String operator;
/** 比较值 */
@Excel(name = "比较值")
private String compareValue;
}

@ -0,0 +1,45 @@
package com.alops.system.domain.vo;
import com.alops.common.annotation.Excel;
import lombok.Data;
@Data
public class equipmentAssessmentVo {
/** 设备唯一标识(设备编号) */
private String id;
/** (设备编号) */
private String equNumber;
/** 设备名称 */
@Excel(name = "设备名称")
private String name;
/** 安装位置 */
@Excel(name = "安装位置 ")
private String location;
/** 设备类型 id */
@Excel(name = "设备类型名称")
private String equType;
/** 设备级别 */
@Excel(name = "设备级别")
private String deviceLevel;
/** CPU使用率(%) */
private String cpuStatus;
/** 内存使用率(%) */
private String memoryStatus;
/** 温度(℃) */
private String temperatureStatus;
/** 健康状态(健康、良好、一般、需维护) */
private String healthStatus;
/** 风险等级 */
private String riskGrade ;
}

@ -0,0 +1,37 @@
package com.alops.system.domain.vo;
import com.alops.common.annotation.Excel;
import lombok.Data;
import java.util.Date;
@Data
public class homeEquAlertMessageVo {
/** 预警级别(1-5级) */
@Excel(name = "预警级别(1-5级)")
private Long level;
/** 发生时间 */
@Excel(name = "发生时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date occurTime;
@Excel(name = "预警信息")
private String message;
/** 处理状态(open、in_progress_closed) */
@Excel(name = "处理状态")
private String status;
@Excel(name = "处理状态")
private String name;
@Excel(name = "处理状态")
private String location;
}

@ -39,17 +39,23 @@ public class queryEquBaseVO {
/** 带外管理 IP */
@Excel(name = "带外管理 IP")
private String ip;
@Excel(name = "设备厂商名称id ")
private String equManuId;
/** 设备厂商 */
@Excel(name = "设备厂商名称 ")
private String manuName;
private String manufacture;
/** 设备厂商 */
@Excel(name = "设备厂商名称 ")
@Excel(name = "设备供应商名称 ")
private String supplierId;
/** 安装位置 id */
@Excel(name = "设备供应商名称 ")
private String supplierName;
/** 安装位置 id */
@Excel(name = "安装位置 id")
private String location;
/** 设备类型 id */
/** 设备类型 id */
@Excel(name = "设备类型id")
private String equTypeId;
@Excel(name = "设备类型名称")
private String equType;
@ -59,7 +65,7 @@ public class queryEquBaseVO {
/** 安装日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "安装日期", width = 30, dateFormat = "yyyy-MM-dd")
@Excel(name = "安装日期", width = 30)
private Date installDate;
/** 预计年限(年) */
@ -78,8 +84,8 @@ public class queryEquBaseVO {
@Excel(name = "健康度")
private BigDecimal health;
/** 添加日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "添加日期", width = 30, dateFormat = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "添加日期", width = 30)
private Date createDate;
/** 启用状态 */
@Excel(name = "启用状态")
@ -88,6 +94,12 @@ public class queryEquBaseVO {
@Excel(name = "累积故障次数")
private String deviceLevel;
@Excel(name = "设备图片")
private String equImage;
@Excel(name = "设备编号")
private String equNumber;
public void setId(String id)
{
@ -226,7 +238,7 @@ public class queryEquBaseVO {
.append("version", getVersion())
.append("ip", getIp())
.append("supplierName", getSupplierName())
.append("manuName", getManuName())
.append("manuName", getManufacture())
.append("location", getLocation())
.append("equType", getEquType())
.append("inCharge", getInCharge())

@ -39,7 +39,23 @@ public class GatherJob implements Job {
try {
if (rule == null) return;
// 按频率判断时间范围
// 1.状态为4时取消调度任务
if (rule.getStatus() == 4) {
Scheduler scheduler = context.getScheduler();
JobKey jobKey = context.getJobDetail().getKey();
scheduler.deleteJob(jobKey);
String Content=String.format("任务执行完此次,已取消后续任务");
iAlertSenderService.sendInternalMessage( Content,"2" );
log.info("规则[{}] 已标记为取消状态(4),对应定时任务已删除: {}", rule.getId(), jobKey);
return;
}
// 2.设置状态为执行中
rule.setStatus(1);
scheduleRulesMapper.updateScheduleRules(rule);
// 3.判断是否执行完成 按频率判断时间范围
if (rule.getRuleType() == 0) {
Date start = rule.getStartTime();
Date end = rule.getEndTime();
@ -48,7 +64,6 @@ public class GatherJob implements Job {
if ( now.after(end)) {
rule.setStatus(2); // 超出范围标记完成
scheduleRulesMapper.updateScheduleRules(rule);
return;
}
}
@ -58,10 +73,17 @@ public class GatherJob implements Job {
iScheduleRulesService.executeImmediately();
// 执行成功
if (rule.getRuleType() == 0 || rule.getRuleType() == 1) {
if (rule.getRuleType() == 1 ) {
rule.setStatus(2);
String Content=String.format("任务执行完成",
rule.getId(), rule.getRuleName());
iAlertSenderService.sendInternalMessage( Content,"2" );
scheduleRulesMapper.updateScheduleRules(rule);
}
scheduleRulesMapper.updateScheduleRules(rule);
} catch (Exception e) {
//执行失败是不会有采集信息和预警信息的

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

@ -2,6 +2,7 @@ package com.alops.system.mapper;
import com.alops.system.domain.AlertRule;
import com.alops.system.domain.dto.AlertRuleAddDto;
import com.alops.system.domain.vo.AlertRuleVo;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.data.repository.query.Param;
@ -26,15 +27,15 @@ public interface AlertRuleMapper
* @param id 请填写功能名称主键
* @return 请填写功能名称
*/
public AlertRule selectAlertRuleById(Long id);
public AlertRuleVo selectAlertRuleById(Long id);
public AlertRule selectAlertRuleByToId(Long id);
/**
* 查询请填写功能名称列表
*
* @param alertRule 请填写功能名称
* @return 请填写功能名称集合
*/
public List<AlertRule> selectAlertRuleList(AlertRule alertRule);
public List<AlertRuleVo> selectAlertRuleList(AlertRule alertRule);
/**
* 新增请填写功能名称

@ -4,19 +4,13 @@ import java.util.List;
import java.util.Map;
import com.alops.system.domain.EquBase;
import com.alops.system.domain.dto.EquBaseQueryDto;
import com.alops.system.domain.dto.MonitorLastDto;
import com.alops.system.domain.dto.MonitorListDto;
import com.alops.system.domain.dto.MonitorStatisticDto;
import com.alops.system.domain.dto.*;
import com.alops.system.domain.vo.imageVo;
import com.alops.system.domain.vo.queryEquBaseVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Update;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Map;
/**
* 设备基本信息Mapper接口
@ -27,6 +21,12 @@ import java.util.Map;
@Mapper
public interface EquBaseMapper
{
/**
* 查询状态为1的设备及其最新采集信息和类型名称
*/
List<equipmentAssessmentDto> getEquipmentAssessmentList();
int incrementCollectCount(@Param("ids") List<String> ids);
@Update("DELETE FROM equ_interface")
@ -63,7 +63,13 @@ public interface EquBaseMapper
MonitorLastDto selectEquMonitorById(String id);
List<Map<String, Object>> selectEquMonitorByIdToList(EquBaseQueryDto queryDto);
List<MonitorListDto> selectEquMonitorList(EquBaseQueryDto equBaseQueryDto);
List<MonitorListDto> selectEquMonitorListPaged();
/**
* 查询每台设备的最新监测信息首页展示用
*/
List<EquMonitorHomeDto> selectLatestEquMonitorList();
/**分类统计界面信息 -YY**/
List<MonitorStatisticDto> selectEquStatisticByType();

@ -17,6 +17,8 @@ public interface ScheduleRulesMapper
public List<ScheduleRules> selectList();
public List<ScheduleRules> selectListOne();
/**
* 查询定时采集规则
*

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

@ -2,6 +2,7 @@ package com.alops.system.service;
import com.alops.system.domain.AlertRule;
import com.alops.system.domain.dto.AlertRuleAddDto;
import com.alops.system.domain.vo.AlertRuleVo;
import java.util.List;
import java.util.Map;
@ -15,7 +16,7 @@ import java.util.Map;
public interface IAlertRuleService
{
public AlertRule saveRule(AlertRuleAddDto dto);
public AlertRuleVo saveRule(AlertRuleAddDto dto);
public AlertRule updateRule(AlertRuleAddDto dto);
@ -40,7 +41,7 @@ public interface IAlertRuleService
* @param alertRule 请填写功能名称
* @return 请填写功能名称集合
*/
public List<AlertRule> selectAlertRuleList(AlertRule alertRule);
public List<AlertRuleVo> selectAlertRuleList(AlertRule alertRule);
/**
* 新增请填写功能名称

@ -3,6 +3,7 @@ package com.alops.system.service;
import com.alops.system.domain.EquBase;
import com.alops.system.domain.dto.EquBaseQueryDto;
import com.alops.system.domain.vo.dropDownVo;
import com.alops.system.domain.vo.equipmentAssessmentVo;
import com.alops.system.domain.vo.imageVo;
import com.alops.system.domain.dto.*;
import com.alops.system.domain.vo.queryEquBaseVO;
@ -18,7 +19,8 @@ import java.util.List;
*/
public interface IEquBaseService
{
//获取设备评估信息
public List<equipmentAssessmentVo> getDeviceIAssessmentnfo();
public List<dropDownVo> selectEquManu();
public List<dropDownVo> selectEquSupp();
@ -60,7 +62,12 @@ public interface IEquBaseService
*/
public List<queryEquBaseVO> selectEquBaseList(EquBaseQueryDto equBase);
public List<MonitorListDto> selectEquMonitorList(EquBaseQueryDto equBaseQueryDto);
public List<MonitorListDto> selectEquMonitorListPaged();
/**
* 查询每台设备的最新监测信息首页展示用
*/
List<EquMonitorHomeDto> selectLatestEquMonitorList();
/**分类统计信息**/
List<MonitorStatisticDto> selectEquStatisticByType();

@ -2,6 +2,8 @@ package com.alops.system.service;
import java.util.List;
import com.alops.system.domain.EquSupplier;
import com.alops.system.domain.dto.EquSupplierAddDto;
import com.alops.system.domain.dto.EquSupplierUpdateDto;
import java.util.List;
@ -31,19 +33,17 @@ public interface IEquSupplierService
/**
* 新增请填写功能名称
*
* @param equSupplier 请填写功能名称
* @return 结果
*/
public int insertEquSupplier(EquSupplier equSupplier);
public int insertEquSupplier(EquSupplierAddDto dto);
/**
* 修改请填写功能名称
*
* @param equSupplier 请填写功能名称
*
* @return 结果
*/
public int updateEquSupplier(EquSupplier equSupplier);
public int updateEquSupplier(EquSupplierUpdateDto updateDto);
/**
* 批量删除请填写功能名称

@ -21,7 +21,9 @@ public interface IScheduleRulesService
public AjaxResult executeRule(ScheduleRules newRule) throws SchedulerException, ExecutionException, InterruptedException;
public Boolean checkRunningOrWaitingRules() throws SchedulerException;
public Boolean executeRule(ScheduleRules newRule) throws SchedulerException, ExecutionException, InterruptedException;
public int executeImmediately() throws ExecutionException, InterruptedException;
/**

@ -153,7 +153,7 @@ public class AlertLaunchServiceImpl implements IAlertLaunchService {
String msgdes = fillTemplate(rule.getAlertTemplate(), row, rule);
msg.setBatch(currentBatch);
msg.setMessage(msgdes);
messages.add(msg);
msgs.add(msgdes);
@ -213,7 +213,7 @@ public class AlertLaunchServiceImpl implements IAlertLaunchService {
// 3. SQL:取每台设备最新记录和次新记录,比较该字段是否变化,并关联设备类型
String sql =
"SELECT g1.*, t.name AS equ_type,b.name AS equ_name" +
"SELECT g1.*, t.name AS equ_type,b.name AS equ_name,b.equ_number" +
"FROM equ_gather g1 " +
"JOIN equ_gather g2 ON g1.equ_id = g2.equ_id " +
"JOIN equ_base b ON g1.equ_id = b.id " +

@ -2,7 +2,6 @@ package com.alops.system.service.impl;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -10,6 +9,9 @@ import java.util.Map;
import com.alops.system.domain.AlertMessage;
import com.alops.system.domain.dto.AlertDto;
import com.alops.system.domain.dto.AlertStatisticDto;
import com.alops.system.domain.dto.LevelCountDto;
import com.alops.system.domain.dto.TypeCountDto;
import com.alops.system.domain.vo.homeEquAlertMessageVo;
import com.alops.system.mapper.AlertMessageMapper;
import com.alops.system.service.IAlertMessageService;
import org.springframework.beans.factory.annotation.Autowired;
@ -51,6 +53,12 @@ public class AlertMessageServiceImpl implements IAlertMessageService
return alertMessageMapper.selectAlertMessageList(alertMessage);
}
@Override
public List<homeEquAlertMessageVo> selectStaticAlertMessageList(){
return alertMessageMapper.selectStaticAlertMessageList();
}
@Override
public List<AlertMessage> selectAlertMessageListByEquId(Long equId)
{
@ -66,18 +74,18 @@ public class AlertMessageServiceImpl implements IAlertMessageService
AlertStatisticDto dto = new AlertStatisticDto();
// 按设备类型统计
Map<String, Integer> typeMap = new HashMap<>();
for (Map<String, Object> row : alertMessageMapper.countByType()) {
typeMap.put((String) row.get("equ_type"), ((Long) row.get("cnt")).intValue());
String name = (String) row.get("equ_type");
Integer count = ((Long) row.get("cnt")).intValue();
dto.getTypeCount().add(new TypeCountDto(name, count));
}
dto.setTypeCount(typeMap);
// 按等级统计
Map<Integer, Integer> levelMap = new HashMap<>();
for (Map<String, Object> row : alertMessageMapper.countByLevel()) {
levelMap.put(((Integer) row.get("level")), ((Long) row.get("cnt")).intValue());
String level = String.valueOf(row.get("level"));
Integer count = ((Long) row.get("cnt")).intValue();
dto.getLevelCount().add(new LevelCountDto(level, count));
}
dto.setLevelCount(levelMap);
// 年 / 月
LocalDate now = LocalDate.now();
@ -90,7 +98,8 @@ public class AlertMessageServiceImpl implements IAlertMessageService
return dto;
}
/**
/**
* 新增故障统计
*
* @param alertMessage 故障统计

@ -8,6 +8,7 @@ import com.alops.common.utils.SecurityUtils;
import com.alops.system.domain.AlertRule;
import com.alops.system.domain.AlertRuleCondition;
import com.alops.system.domain.dto.AlertRuleAddDto;
import com.alops.system.domain.vo.AlertRuleVo;
import com.alops.system.mapper.AlertRuleConditionMapper;
import com.alops.system.mapper.AlertRuleMapper;
import com.alops.system.service.IAlertRuleService;
@ -37,7 +38,7 @@ public class AlertRuleServiceImpl implements IAlertRuleService
*/
@Override
public AlertRule saveRule(AlertRuleAddDto dto) {
public AlertRuleVo saveRule(AlertRuleAddDto dto) {
Long userId = SecurityUtils.getLoginUser().getUserId();
AlertRule rule = dto.getAlertRule();
@ -56,7 +57,7 @@ public class AlertRuleServiceImpl implements IAlertRuleService
sql = buildSql(rule, conditions);
}
rule.setAlertSql(sql);
rule.setEnable(1);
// 插入规则
alertRuleMapper.insertAlertRule(rule);
@ -67,7 +68,7 @@ public class AlertRuleServiceImpl implements IAlertRuleService
alertRuleConditionMapper.insertAlertRuleCondition(c);
}
}
AlertRule fullRule = alertRuleMapper.selectAlertRuleById(rule.getId());
AlertRuleVo fullRule = alertRuleMapper.selectAlertRuleById(rule.getId());
return fullRule;
}
@ -104,14 +105,14 @@ public class AlertRuleServiceImpl implements IAlertRuleService
alertRuleConditionMapper.insertAlertRuleCondition(c);
}
}
AlertRule fullRule = alertRuleMapper.selectAlertRuleById(rule.getId());
AlertRule fullRule = alertRuleMapper.selectAlertRuleByToId(rule.getId());
return fullRule;
}
@Override
public AlertRuleAddDto selectDetailAlertRuleById(Long id) {
// 1. 查询主表
AlertRule rule = alertRuleMapper.selectAlertRuleById(id);
AlertRule rule = alertRuleMapper.selectAlertRuleByToId(id);
if (rule == null) {
return null;
}
@ -140,7 +141,7 @@ public class AlertRuleServiceImpl implements IAlertRuleService
if ("equ_gather".equalsIgnoreCase(rule.getTableName())) {
// equ_gather 作为主表
sql.append("g.*, t.name AS equ_type ,b.name AS equ_name")
sql.append("g.*, t.name AS equ_type ,b.name AS equ_name,b.equ_number ")
.append("FROM equ_gather g ")
.append("JOIN equ_base b ON g.equ_id = b.id ")
.append("JOIN equ_type t ON b.equ_type = t.id ") // ★ 新增关联
@ -153,7 +154,7 @@ public class AlertRuleServiceImpl implements IAlertRuleService
.append(buildConditionsSql(conditions));
} else {
// 其他表,需要连 equ_gather → equ_base → equ_type
sql.append("src.*, g.equ_id, t.name AS equ_type,b.name AS equ_name ")
sql.append("src.*, g.equ_id, t.name AS equ_type,b.name AS equ_name,b.equ_number ")
.append("FROM ").append(rule.getTableName()).append(" src ")
.append("JOIN equ_gather g ON src.equ_gather_id = g.id ")
.append("JOIN equ_base b ON g.equ_id = b.id ")
@ -316,7 +317,7 @@ public class AlertRuleServiceImpl implements IAlertRuleService
@Override
public AlertRule selectAlertRuleById(Long id)
{
return alertRuleMapper.selectAlertRuleById(id);
return alertRuleMapper.selectAlertRuleByToId(id);
}
/**
@ -326,7 +327,7 @@ public class AlertRuleServiceImpl implements IAlertRuleService
* @return 请填写功能名称
*/
@Override
public List<AlertRule> selectAlertRuleList(AlertRule alertRule)
public List<AlertRuleVo> selectAlertRuleList(AlertRule alertRule)
{
return alertRuleMapper.selectAlertRuleList(alertRule);
}

@ -1,16 +1,13 @@
package com.alops.system.service.impl;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.math.BigDecimal;
import java.util.*;
import com.alops.common.utils.SecurityUtils;
import com.alops.system.domain.EquBase;
import com.alops.system.domain.EquSupplier;
import com.alops.system.domain.EquType;
import com.alops.system.domain.dto.EquBaseQueryDto;
import com.alops.system.domain.vo.dropDownVo;
import com.alops.system.domain.vo.equipmentAssessmentVo;
import com.alops.system.domain.vo.imageVo;
import com.alops.system.domain.dto.*;
import com.alops.system.domain.vo.queryEquBaseVO;
@ -55,6 +52,54 @@ public class EquBaseServiceImpl implements IEquBaseService
return equSupplierMapper.selectEquSupDropDown();
}
//设备评估信息
@Override
public List<equipmentAssessmentVo> getDeviceIAssessmentnfo(){
List<equipmentAssessmentDto> equAsstDtoList = equBaseMapper.getEquipmentAssessmentList();
List<equipmentAssessmentVo> resultList = new ArrayList<>();
for (equipmentAssessmentDto dto : equAsstDtoList) {
equipmentAssessmentVo vo = new equipmentAssessmentVo();
vo.setId(dto.getId());
vo.setEquNumber(dto.getEquNumber());
vo.setName(dto.getName());
vo.setLocation(dto.getLocation());
vo.setEquType(dto.getEquType());
vo.setDeviceLevel(dto.getDeviceLevel());
// 四项指标
String cpuStatus = checkStatus(dto.getCpuUtilization(), 80, 90, 95);
String memoryStatus = checkStatus(dto.getMemoryUtilization(), 80, 90, 95);
String temperatureStatus = checkTemperatureStatus(dto.getTemperature());
String healthStatus = checkHealthStatus(dto.getHealth());
vo.setCpuStatus(cpuStatus);
vo.setMemoryStatus(memoryStatus);
vo.setTemperatureStatus(temperatureStatus);
vo.setHealthStatus(healthStatus);
// 风险等级 = 四项指标中最严重的
int riskLevel = Math.max(
Math.max(getRisk(cpuStatus), getRisk(memoryStatus)),
Math.max(getRisk(temperatureStatus), getRisk(healthStatus))
);
vo.setRiskGrade(switch (riskLevel) {
case 1 -> "无风险";
case 2 -> "低";
case 3 -> "中";
case 4 -> "高";
default -> "未知";
});
resultList.add(vo);
}
return resultList;
}
@Autowired
private EquInterfaceMapper interfaceMapper;
/**
@ -110,14 +155,16 @@ public class EquBaseServiceImpl implements IEquBaseService
MonitorHistoryDto dto = new MonitorHistoryDto();
for (Map<String, Object> row : rows) {
dto.getTemperatureList().add(row.get("temperature_value") != null ? ((Number) row.get("temperature_value")).floatValue() : null);
dto.getInvoltageList().add(row.get("involtage_value") != null ? ((Number) row.get("involtage_value")).floatValue() : null);
dto.getOutvoltageList().add(row.get("outvoltage_value") != null ? ((Number) row.get("outvoltage_value")).floatValue() : null);
dto.getTimeList().add(row.get("gather_time").toString());
dto.getMemoryList().add(row.get("memory_value") != null ? ((Number) row.get("memory_value")).floatValue() : null);
dto.getCpuList().add(row.get("cpu_value") != null ? ((Number) row.get("cpu_value")).floatValue() : null);
dto.getHealthList().add(row.get("health_value") != null ? ((Number) row.get("health_value")).floatValue() : null);
dto.getTimeList().add(row.get("gather_time") != null ? row.get("gather_time").toString() : null);
}
return dto;
}
/**
* 查询设备基本信息列表
*
@ -131,21 +178,101 @@ public class EquBaseServiceImpl implements IEquBaseService
}
/**
* 查询多台显示界面的单独信息
* 查询多台设备的最新监测信息
**/
@Override
public List<MonitorListDto> selectEquMonitorListPaged() {
return equBaseMapper.selectEquMonitorListPaged();
}
/**
* 查询多台设备的最新监测信息首页展示
**/
@Override
public List<MonitorListDto> selectEquMonitorList(EquBaseQueryDto equBaseQueryDto) {
return equBaseMapper.selectEquMonitorList(equBaseQueryDto);
public List<EquMonitorHomeDto> selectLatestEquMonitorList() {
return equBaseMapper.selectLatestEquMonitorList();
}
/**
* 设备类型分类统计信息
**/
@Override
public List<MonitorStatisticDto> selectEquStatisticByType() {
return equBaseMapper.selectEquStatisticByType();
List<MonitorStatisticDto> list = equBaseMapper.selectEquStatisticByType();
if (list == null || list.isEmpty()) {
return list;
}
// 计算每种类型的数量
int totalCount = 0;
for (MonitorStatisticDto dto : list) {
int count = (dto.getDevices() != null) ? dto.getDevices().size() : 0;
dto.setCount(count);
totalCount += count;
}
// 计算百分比
for (MonitorStatisticDto dto : list) {
if (totalCount > 0) {
double percent = (dto.getCount() * 100.0) / totalCount;
dto.setPercentage(Math.round(percent * 100.0) / 100.0); // 保留两位小数
} else {
dto.setPercentage(0.0);
}
}
this.totalDeviceCount = totalCount; // 注意:你可以在 service 中定义字段存储
return list;
}
// 在类中增加:
private int totalDeviceCount;
public int getTotalDeviceCount() {
return totalDeviceCount;
}
/** 通用百分比指标判断(CPU/内存) */
private String checkStatus(BigDecimal val, double healthy, double good, double average) {
if (val == null) return "未知";
double v = val.doubleValue();
if (v < healthy) return "健康";
if (v < good) return "良好";
if (v < average) return "一般";
return "需维护";
}
/** 温度判断 */
private String checkTemperatureStatus(BigDecimal temp) {
if (temp == null) return "未知";
double val = temp.doubleValue();
if (val >= 25 && val <= 45) return "健康";
if ((val >= 20 && val < 25) || (val > 45 && val <= 50)) return "良好";
if ((val >= 16 && val < 20) || (val > 50 && val <= 55)) return "一般";
return "需维护";
}
/** 健康度判断 */
private String checkHealthStatus(BigDecimal health) {
if (health == null) return "未知";
return switch (health.intValue()) {
case 1 -> "健康";
case 2 -> "良好";
case 3 -> "一般";
case 4 -> "需维护";
default -> "未知";
};
}
/** 风险等级映射:健康=1,良好=2,一般=3,需维护=4 */
private int getRisk(String status) {
return switch (status) {
case "健康" -> 1;
case "良好" -> 2;
case "一般" -> 3;
case "需维护" -> 4;
default -> 0;
};
}
/**
@ -160,6 +287,7 @@ public class EquBaseServiceImpl implements IEquBaseService
if (equBase.getCreateDate() == null) {
equBase.setCreateDate(new Date());
}
equBase.setId(UUID.randomUUID().toString());
equBase.setCreateBy(SecurityUtils.getLoginUser().getUserId());
return equBaseMapper.insertEquBase(equBase);
}

@ -59,7 +59,8 @@ public class EquManuServiceImpl implements IEquManuService
{
equManu.setId(UUID.randomUUID().toString());
equManu.setCreateDate(new Date());
Long userId = SecurityUtils.getLoginUser().getUserId();
String userName = SecurityUtils.getLoginUser().getUser().getUserName();
equManu.setCreateBy(userName);
return equManuMapper.insertEquManu(equManu);
}
@ -72,7 +73,8 @@ public class EquManuServiceImpl implements IEquManuService
@Override
public int updateEquManu(EquManu equManu)
{
Long userId = SecurityUtils.getLoginUser().getUserId();
String userName = SecurityUtils.getLoginUser().getUser().getUserName();
equManu.setCreateBy(userName);
return equManuMapper.updateEquManu(equManu);
}

@ -2,8 +2,12 @@ package com.alops.system.service.impl;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import com.alops.common.utils.DateUtils;
import com.alops.common.utils.SecurityUtils;
import com.alops.system.domain.dto.EquSupplierAddDto;
import com.alops.system.domain.dto.EquSupplierUpdateDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alops.system.mapper.EquSupplierMapper;
@ -53,26 +57,52 @@ public class EquSupplierServiceImpl implements IEquSupplierService
/**
* 新增请填写功能名称
*
* @param equSupplier 请填写功能名称
*
* @return 结果
*/
@Override
public int insertEquSupplier(EquSupplier equSupplier)
public int insertEquSupplier(EquSupplierAddDto dto)
{
equSupplier.setCreateTime(new Date());
EquSupplier equSupplier = new EquSupplier();
// DTO 转换到实体
equSupplier.setId(UUID.randomUUID().toString()); // 自动生成 id
equSupplier.setName(dto.getName());
equSupplier.setDescription(dto.getDescription());
equSupplier.setContactBy(dto.getContactBy());
equSupplier.setContactWay(dto.getContactWay());
equSupplier.setCreateTime(new Date()); // 自动生成创建时间
equSupplier.setStatus(dto.getStatus());
String userName = SecurityUtils.getLoginUser().getUser().getUserName();
equSupplier.setCreateBy(userName);
return equSupplierMapper.insertEquSupplier(equSupplier);
}
/**
* 修改请填写功能名称
*
* @param equSupplier 请填写功能名称
* @return 结果
*/
@Override
public int updateEquSupplier(EquSupplier equSupplier)
{
public int updateEquSupplier(EquSupplierUpdateDto updateDto) {
// 将 DTO 转换成 Entity
EquSupplier equSupplier = new EquSupplier();
equSupplier.setId(updateDto.getId());
equSupplier.setName(updateDto.getName());
equSupplier.setDescription(updateDto.getDescription());
equSupplier.setContactBy(updateDto.getContactBy());
equSupplier.setContactWay(updateDto.getContactWay());
equSupplier.setStatus(updateDto.getStatus());
// 后端自动设置修改时间
equSupplier.setCreateTime(new Date());
String userName = SecurityUtils.getLoginUser().getUser().getUserName();
equSupplier.setCreateBy(userName);
return equSupplierMapper.updateEquSupplier(equSupplier);
}

@ -56,7 +56,8 @@ public class EquTypeServiceImpl implements IEquTypeService
public int insertEquType(EquType equType)
{
equType.setId(UUID.randomUUID().toString());
Long userId = SecurityUtils.getLoginUser().getUserId();
String userName = SecurityUtils.getLoginUser().getUser().getUserName();
equType.setCreateBy(userName);
return equTypeMapper.insertEquType(equType);
}
@ -69,7 +70,8 @@ public class EquTypeServiceImpl implements IEquTypeService
@Override
public int updateEquType(EquType equType)
{
Long userId = SecurityUtils.getLoginUser().getUserId();
String userName = SecurityUtils.getLoginUser().getUser().getUserName();
equType.setCreateBy(userName);
return equTypeMapper.updateEquType(equType);
}

@ -5,10 +5,7 @@ import java.sql.SQLOutput;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import com.alops.common.core.domain.AjaxResult;
@ -25,6 +22,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@ -57,69 +55,117 @@ public class ScheduleRulesServiceImpl implements IScheduleRulesService {
@Autowired
private MemoryToolService memoryToolService;
@Autowired
private IAlertSenderService iAlertSenderService;
private static final Logger log = LoggerFactory.getLogger(ScheduleRulesServiceImpl.class);
@Override
public AjaxResult executeRule(ScheduleRules newRule) throws SchedulerException, ExecutionException, InterruptedException {
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Boolean checkRunningOrWaitingRules() throws SchedulerException {
// 1. 获取所有正在执行(1)和待执行(0)的规则
List<ScheduleRules> runningOrWaiting = scheduleRulesMapper.selectList();
if (runningOrWaiting!=null) {
for (ScheduleRules rule : runningOrWaiting) {
switch (rule.getStatus()) {
case 1: // 正在执行
log.info("规则[{}]:正在执行上一个任务,等待上一个任务完成……", rule.getId());
waitTaskFinish(rule.getId());
log.info("规则[{}]:完成上一个任务任务,开始新的任务…", rule.getId());
if (rule.getRuleType() == 2 || rule.getRuleType() == 1) {
rule.setStatus(2);
} else if (rule.getRuleType() == 0) {
log.info("改变状态为4");
rule.setStatus(4);
}
scheduleRulesMapper.updateScheduleRules(rule);
break;
return true;
case 0: // 待执行
if (rule.getRuleType() == 0 || rule.getRuleType() == 1) {
quartzService.deleteJob(rule.getId());
}
rule.setStatus(4);
scheduleRulesMapper.updateScheduleRules(rule);
break;
return false;
default:
break;
return true;
}
}
}
// 2. 执行新规则
return false;
}
//首先存入规则在执行
Date now = new Date();
Long userId = SecurityUtils.getLoginUser().getUserId();
newRule.setCreatedBy(userId);
newRule.setCreatedAt(now);
newRule.setStatus(0);
scheduleRulesMapper.insertScheduleRules(newRule);
switch (newRule.getRuleType().toString()) {
case "2": // 立即执行
newRule.setStatus(1);
scheduleRulesMapper.updateScheduleRules(newRule);
try {
executeImmediately();
newRule.setStatus(2);
scheduleRulesMapper.updateScheduleRules(newRule);
return AjaxResult.success("立即执行任务成功:"); // 异常会抛出,前端收到
} catch (Exception e) {
newRule.setStatus(3);
@Override
public Boolean executeRule(ScheduleRules newRule) throws SchedulerException, ExecutionException, InterruptedException {
// // 1. 获取所有正在执行(1)和待执行(0)的规则
// List<ScheduleRules> runningOrWaiting = scheduleRulesMapper.selectList();
// if (runningOrWaiting!=null) {
// for (ScheduleRules rule : runningOrWaiting) {
// switch (rule.getStatus()) {
// case 1: // 正在执行
// log.info("规则[{}]:正在执行上一个任务,等待上一个任务完成……", rule.getId());
// waitTaskFinish(rule.getId());
// log.info("规则[{}]:完成上一个任务任务,开始新的任务…", rule.getId());
// if (rule.getRuleType() == 2 || rule.getRuleType() == 1) {
// rule.setStatus(2);
// } else if (rule.getRuleType() == 0) {
// rule.setStatus(4);
// }
// scheduleRulesMapper.updateScheduleRules(rule);
// break;
// case 0: // 待执行
// if (rule.getRuleType() == 0 || rule.getRuleType() == 1) {
// quartzService.deleteJob(rule.getId());
// }
// rule.setStatus(4);
// scheduleRulesMapper.updateScheduleRules(rule);
// break;
// default:
// break;
// }
// }
// }
// 2. 执行新规则
try {
Date now = new Date();
Long userId = SecurityUtils.getLoginUser().getUserId();
// 1. 初始化规则
newRule.setCreatedBy(userId);
newRule.setCreatedAt(now);
newRule.setStatus(0);
scheduleRulesMapper.insertScheduleRules(newRule); // 插入成功与否决定返回值
switch (newRule.getRuleType().toString()) {
case "2": // 立即执行
newRule.setStatus(1); // 执行中
scheduleRulesMapper.updateScheduleRules(newRule);
// 只捕获立即执行异常
return AjaxResult.error("立即执行任务失败:" + e.getMessage());
}
// 异步立即执行采集任务
CompletableFuture.runAsync(() -> {
try {
executeImmediately(); // 实际采集逻辑
newRule.setStatus(2); // 执行成功
scheduleRulesMapper.updateScheduleRules(newRule);
String content = String.format("立即任务 [%s] 执行完成", newRule.getRuleName());
iAlertSenderService.sendInternalMessage(content, "2");
} catch (Exception e) {
newRule.setStatus(3); // 执行失败
scheduleRulesMapper.updateScheduleRules(newRule);
String content = String.format("立即任务 [%s] 执行失败:%s", newRule.getRuleName(), e.getMessage());
try {
iAlertSenderService.sendInternalMessage(content, "2");
} catch (Exception ne) {
log.error("发送站内信失败: {}", ne.getMessage(), ne);
}
}
});
break;
case "1": // 固定时间
newRule.setStatus(0);
scheduleRulesMapper.updateScheduleRules(newRule);
@ -136,10 +182,14 @@ public class ScheduleRulesServiceImpl implements IScheduleRulesService {
quartzService.createOrUpdateJob(newRule);
}
break;
default:
throw new IllegalArgumentException("Unsupported rule type");
default:
throw new IllegalArgumentException("Unsupported rule type");
}
return true; // 插入和调度成功
} catch (Exception e) {
log.error("规则设置失败: {}", e.getMessage(), e);
return false; // 插入或调度失败
}
return null;
}
/**
@ -163,7 +213,7 @@ public class ScheduleRulesServiceImpl implements IScheduleRulesService {
Map<String, List<EquOid>> oidMap = new HashMap<>();
for (EquBase dev : devices) {
oidMap.put(dev.getManufacture(), equOidMapper.findByManuIdAndStatus(dev.getManufacture()));
oidMap.put(dev.getEquManuId(), equOidMapper.findByManuIdAndStatus(dev.getEquManuId()));
}
ExecutorService executor = Executors.newFixedThreadPool(10);
@ -172,7 +222,7 @@ public class ScheduleRulesServiceImpl implements IScheduleRulesService {
for (EquBase device : devices) {
futures.add(executor.submit(() -> {
long start = System.currentTimeMillis();
List<EquOid> oids = oidMap.getOrDefault(device.getManufacture(), Collections.emptyList());
List<EquOid> oids = oidMap.getOrDefault(device.getEquManuId(), Collections.emptyList());
Map<String, Object> snmpResults = snmpService.query(device.getIp(), oids);
long afterSnmp = System.currentTimeMillis();
System.out.println("SNMP查询耗时: " + (afterSnmp - start) + " ms");
@ -243,6 +293,7 @@ public class ScheduleRulesServiceImpl implements IScheduleRulesService {
// 执行最新预警
iAlertLaunchService.executeImmediateAlerts();
log.info("采集完一次!!!");
return result;
}

@ -19,7 +19,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="handleTime" column="handle_time" />
<result property="status" column="status" />
<result property="batch" column="batch" />
<result property="message" column="message" />
</resultMap>
<select id="selectMaxBatch" resultType="integer">
@ -30,12 +30,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<insert id="batchInsert" parameterType="java.util.List">
INSERT INTO alert_message
(equ_id, type, equ_type, solution, level, occur_time, handler, handle_time, status,batch)
(equ_id, type, equ_type, solution, level, occur_time, handler, handle_time, status,batch,message)
VALUES
<foreach collection="list" item="msg" separator=",">
(#{msg.equId},#{msg.type}, #{msg.equType},
#{msg.solution}, #{msg.level}, #{msg.occurTime},
#{msg.handler}, #{msg.handleTime}, #{msg.status}, #{msg.batch})
#{msg.handler}, #{msg.handleTime}, #{msg.status}, #{msg.batch}, #{msg.message})
</foreach>
</insert>
@ -52,13 +52,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
am.handler,
am.handle_time,
am.status,
am.batch
am.batch,
am.message
FROM alert_message am
LEFT JOIN equ_base eb ON am.equ_id = eb.id
</sql>
<sql id="selectAlertMessageVoJoinGather">
select a.id, g.equ_id, type, equ_type solution, level, occur_time, handler, handle_time, status,batch 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>
<select id="selectAlertMessageList" parameterType="AlertDto" resultMap="AlertMessageResult">
@ -83,7 +84,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<!-- 按 batch 从大到小排序 -->
ORDER BY am.batch DESC
</select>
<!-- 查询最新预警信息(按时间排序,取前N条) -->
<select id="selectStaticAlertMessageList" resultType="homeEquAlertMessageVo">
SELECT
a.level,
a.occur_time AS occurTime,
a.status,
a.message,
e.name,
e.location
FROM alert_message a
LEFT JOIN equ_base e ON a.equ_id = e.id
ORDER BY a.occur_time DESC
</select>
<select id="selectAlertMessageById" parameterType="Long" resultMap="AlertMessageResult">
<include refid="selectAlertMessageVo"/>
where am.id = #{id}

@ -31,18 +31,44 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<sql id="selectAlertRuleVo">
SELECT
ar.id,
ar.rule_name,
ar.rule_name AS ruleName,
ar.severity,
ar.alert_way,
ar.alert_station,
ar.alert_way AS alertWay,
ar.alert_station AS alertStation,
ar.description,
ar.enable,
ar.create_time,
ar.update_time,
su1.user_name AS create_by,
su2.user_name AS update_by,
ar.table_name,
ar.alert_sql,
ar.create_time as createTime,
ar.update_time as updateTime,
su1.user_name AS createBy,
su2.user_name AS updateBy,
ar.table_name as tableName,
ar.alert_sql AS alertSql,
ar.alert_template AS alertTemplate,
ar.type,
ac.param_name AS paramName,
ac.operator,
ac.compare_value AS compareValue
FROM alert_rule ar
LEFT JOIN sys_user su1 ON ar.create_by = su1.user_id
LEFT JOIN sys_user su2 ON ar.update_by = su2.user_id
LEFT JOIN alert_rule_condition ac ON ar.id = ac.alert_rule_id
</sql>
<sql id="selectAlertRuleVo2">
SELECT
ar.id,
ar.rule_name ,
ar.severity,
ar.alert_way ,
ar.alert_station ,
ar.description,
ar.enable,
ar.create_time ,
ar.update_time ,
su1.user_name as create_by,
su2.user_name as update_by,
ar.table_name ,
ar.alert_sql ,
ar.alert_template,
ar.type
FROM alert_rule ar
@ -50,7 +76,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
LEFT JOIN sys_user su2 ON ar.update_by = su2.user_id
</sql>
<select id="selectAlertRuleList" parameterType="AlertRule" resultMap="AlertRuleResult">
<select id="selectAlertRuleList" parameterType="AlertRule" resultType="alertRuleVo">
<include refid="selectAlertRuleVo"/>
<where>
<if test="ruleName != null and ruleName != ''"> and ar.rule_name like concat('%', #{ruleName}, '%')</if>
@ -65,9 +91,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectAlertRuleById" parameterType="Long" resultMap="AlertRuleResult">
<select id="selectAlertRuleById" parameterType="Long" resultType="AlertRuleVo">
<include refid="selectAlertRuleVo"/>
where id = #{id}
where ar.id = #{id}
</select>
<select id="selectAlertRuleByToId" parameterType="Long" resultMap="AlertRuleResult">
<include refid="selectAlertRuleVo2"/>
where ar.id = #{id}
</select>
<insert id="insertAlertRule" parameterType="AlertRule" useGeneratedKeys="true" keyProperty="id">

@ -9,9 +9,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="name" column="name" />
<result property="version" column="version" />
<result property="ip" column="ip" />
<result property="manufacture" column="manufacture" />
<result property="equManuId" column="manufacture" />
<result property="location" column="location" />
<result property="equType" column="equ_type" />
<result property="equTypeId" column="equ_type" />
<result property="inCharge" column="in_charge" />
<result property="installDate" column="install_date" />
<result property="lifeCycle" column="life_cycle" />
@ -24,29 +24,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="supplierId" column="supplier_id" />
<result property="gatherFrequency" column="gather_frequency" />
<result property="equImage" column="equ_image" />
<result property="repairFrequency" column="repair_frequency" />
<result property="repairCost" column="repair_cost" />
<result property="fanSpeed" column="fan_speed"/>
<result property="cpuUtilization" column="cpu_utilization"/>
<result property="memoryUtilization" column="memory_utilization"/>
<result property="health" column="health"/>
<result property="contWorkPeriod" column="cont_work_period"/>
<result property="equNumber" column="equ_number" />
<association property="manufactureVO" columnPrefix="equ_manu_" autoMapping="true" />
<association property="equTypeVO" columnPrefix="equ_type_" autoMapping="true" />
<collection property="temperatureList" javaType="java.util.ArrayList" ofType="java.lang.Float">
<result column="temperature_value"/>
</collection>
<collection property="involtageList" javaType="java.util.ArrayList" ofType="java.lang.Float">
<result column="involtage_value"/>
</collection>
<collection property="outvoltageList" javaType="java.util.ArrayList" ofType="java.lang.Float">
<result column="outvoltage_value"/>
</collection>
<!-- <association property="manufacture" columnPrefix="equ_manu_" autoMapping="true" />-->
</resultMap>
<resultMap id="EquMonitorResult" type="com.alops.system.domain.vo.EquMonitorVO">
<result property="id" column="id" />
@ -57,23 +43,22 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="location" column="location" />
<result property="equType" column="equ_type" />
<result property="inCharge" column="in_charge" />
<result property="releaseDate" column="release_date" />
<result property="installDate" column="install_date" />
<result property="lifeCycle" column="life_cycle" />
<result property="serviceTime" column="service_time" />
<result property="warranty" column="warranty" />
<result property="createBy" column="create_by" />
<result property="createDate" column="create_date" />
<result property="updateBy" column="update_by" />
<result property="updateDate" column="update_date" />
<result property="status" column="status" />
<result property="failureFrequency" column="failure_frequency" />
<result property="repairFrequency" column="repair_frequency" />
<result property="repairCost" column="repair_cost" />
<result property="fanSpeed" column="fan_speed"/>
<result property="cpuUtilization" column="cpu_utilization"/>
<result property="memoryUtilization" column="memory_utilization"/>
<result property="health" column="health"/>
<result property="equImage" column="equ_image" />
<result property="equNumber" column="equ_number" />
<result property="contWorkPeriod" column="cont_work_period"/>
<association property="manufactureVO" columnPrefix="equ_manu_" autoMapping="true" />
<association property="equTypeVO" columnPrefix="equ_type_" autoMapping="true" />
@ -91,7 +76,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectEquBaseVo">
select id, name, version, ip, manufacture, location, equ_type, in_charge, install_date, life_cycle, warranty, create_by, create_date, status, device_level, supplier_id from equ_base
select id,equ_number, name, version, ip, manufacture, location, equ_type, in_charge, install_date, life_cycle, warranty, create_by, create_date, status, device_level, supplier_id from equ_base
</sql>
@ -105,6 +90,45 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</update>
<select id="getEquipmentAssessmentList"
resultType="com.alops.system.domain.dto.equipmentAssessmentDto">
SELECT
b.id AS id,
b.equ_number AS equNumber,
b.name AS name,
b.location AS location,
t.name AS equType, -- 从 equ_type 表取类型名称
b.device_level AS deviceLevel,
-- 从 equ_gather 最新一条记录中取数据
g.health AS health,
g.temperature AS temperature,
g.cpu_utilization AS cpuUtilization,
g.memory_utilization AS memoryUtilization
FROM equ_base b
LEFT JOIN equ_type t
ON b.equ_type = t.id
LEFT JOIN (
SELECT eg1.*
FROM equ_gather eg1
INNER JOIN (
SELECT equ_id, MAX(gather_time) AS max_time
FROM equ_gather
GROUP BY equ_id
) eg2
ON eg1.equ_id = eg2.equ_id AND eg1.gather_time = eg2.max_time
) g
ON b.id = g.equ_id
WHERE b.status = 1
ORDER BY b.id
</select>
<select id="findEquBaseList" resultMap="EquBaseResult">
<include refid="selectEquBaseVo"/>
<where>
@ -114,13 +138,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<!-- 查询列 -->
<sql id="selectEquBaseVo2">
b.id AS id,
b.id AS id,
b.equ_number AS equNumber,
b.name AS name,
b.version AS version,
b.ip AS ip,
m.name AS manuName,
b.manufacture AS equManuId,
m.name AS manufacture,
b.supplier_id AS supplierId,
s.name AS supplierName,
b.location AS location,
b.equ_type AS equTypeId,
t.name AS equType,
b.in_charge AS inCharge,
b.install_date AS installDate,
@ -130,7 +158,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
b.create_date AS createDate,
b.status AS status,
b.device_level AS deviceLevel,
g.health AS health
g.health AS health,
b.equ_image AS equImage
</sql>
<select id="selectEquBaseList" parameterType="equBaseQueryDto" resultType="com.alops.system.domain.vo.queryEquBaseVO">
@ -152,100 +181,141 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
) tmp ON eg.equ_id = tmp.equ_id AND eg.gather_time = tmp.max_time
) g ON b.id = g.equ_id
<where>
<if test="name != null and name != ''">
AND b.name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="location != null and location != ''">
AND b.location LIKE CONCAT('%', #{location}, '%')
</if>
<if test="minTime != null">
AND b.create_date &gt;= #{minTime}
</if>
<if test="maxTime != null">
AND b.create_date &lt;= #{maxTime}
</if>
<if test="status != null">
AND b.status = #{status}
</if>
</where>
</select>
<select id="selectEquMonitorList" parameterType="EquBaseQueryDto" resultType="MonitorListDto">
<select id="selectEquMonitorListPaged" resultType="MonitorListDto">
SELECT
b.id,
b.name,
b.version,
b.device_level,
b.location,
b.status,
g.cpu_utilization,
g.health,
g.fan_speed,
b.failure_frequency,
b.equ_image
FROM equ_base b
LEFT JOIN equ_gather g ON b.id = g.equ_id
<where>
g.cpu_utilization is not null
<if test="equType != null and equType != ''">
AND b.equ_type = #{equType}
</if>
<if test="equName != null and equName != ''">
AND b.name LIKE concat('%', #{equName}, '%')
</if>
<if test="location != null and location != ''">
AND b.location = #{location}
</if>
<if test="manufacture != null and manufacture != ''">
AND b.manufacture = #{manufacture}
</if>
<if test="inCharge != null">
AND b.in_charge = #{inCharge}
</if>
<if test="status != null">
AND b.status = #{status}
</if>
<if test="minTime != null">
AND b.create_date <![CDATA[>=]]> #{minTime}
</if>
<if test="maxTime != null">
AND b.create_date <![CDATA[<=]]> #{maxTime}
</if>
<if test="health != null">
AND g.health <![CDATA[>=]]> #{health}
</if>
</where>
ORDER BY g.gather_time desc limit 1
c.id,
c.name,
c.ip,
c.equTypeId,
c.equTypeName,
c.equManuId,
c.equManuName,
c.version,
c.deviceLevel,
c.location,
c.status,
c.cpuUtilization,
c.health,
c.fanSpeed,
c.contWorkPeriod,
c.unhandledAlertCount,
c.AlertCount
FROM (
SELECT
b.id,
b.name,
b.ip,
b.equ_type AS equTypeId,
t.name AS equTypeName,
b.manufacture AS equManuId,
m.name AS equManuName,
b.version,
b.device_level AS deviceLevel,
b.location,
b.status,
g.cpu_utilization AS cpuUtilization,
g.health,
g.fan_speed AS fanSpeed,
g.cont_work_period AS contWorkPeriod,
(SELECT COUNT(1)
FROM alert_message a
WHERE a.equ_id = b.id AND a.status = 'UNHANDLED') AS unhandledAlertCount,
(SELECT COUNT(1)
FROM alert_message a
WHERE a.equ_id = b.id ) AS AlertCount,
ROW_NUMBER() OVER (PARTITION BY b.id ORDER BY g.gather_time DESC) AS rn
FROM equ_base b
LEFT JOIN equ_type t ON b.equ_type = t.id
LEFT JOIN equ_manu m ON b.manufacture = m.id
LEFT JOIN equ_gather g ON b.id = g.equ_id
) c
WHERE c.rn = 1
ORDER BY c.id
</select>
<select id="selectLatestEquMonitorList" resultType="com.alops.system.domain.dto.EquMonitorHomeDto">
SELECT
t.id,
t.equNumber,
t.name,
t.location,
t.cpuUtilization,
t.memoryUtilization,
t.temperature,
t.health,
t.contWorkPeriod,
t.gatherTime
FROM (
SELECT
b.id,
b.equ_number as equNumber,
b.name,
b.location,
g.cpu_utilization AS cpuUtilization,
g.memory_utilization AS memoryUtilization,
g.temperature,
g.health,
g.cont_work_period AS contWorkPeriod,
g.gather_time AS gatherTime,
ROW_NUMBER() OVER (PARTITION BY b.id ORDER BY g.gather_time DESC) AS rn
FROM equ_base b
LEFT JOIN equ_gather g ON b.id = g.equ_id
) t
WHERE t.rn = 1
ORDER BY t.name
</select>
<select id="selectEquMonitorById" parameterType="string" resultType="MonitorLastDto">
SELECT
g.cont_work_period,
g.cont_work_period AS contWorkPeriod,
b.equ_image AS equImage,
b.id,
b.equ_number as equNumber,
b.name,
b.version,
b.device_level,
t.name as equ_type,
m.name as manufacture,
s.name as supplier_id,
#b.release_date,
b.device_level AS deviceLevel,
b.equ_type as equTypeId,
t.name as equTypeName,
b.status,
b.manufacture as equManuId,
m.name as equManuName,
b.supplier_id as supplierId,
s.name as supplierName,
s.contact_by AS ContactBy,
s.contact_way AS ContactWay,
b.warranty,
m.contact_by as manufacture,
m.contact_way as manufacture,
b.ip,
b.location,
b.install_date,
#b.service_time,
b.in_charge,
b.failure_frequency,
#b.repair_frequency,
#b.service_time/warranty AS aging,
g.fan_speed,
g.cpu_utilization,
g.memory_utilization,
g.health
b.install_date AS installDate,
b.in_charge AS inCharge,
(SELECT COUNT(1)
FROM alert_message a
WHERE a.equ_id = b.id ) AS AlertCount,
-- 新增列:统计未处理告警数量
(SELECT COUNT(1)
FROM alert_message a
WHERE a.equ_id = b.id AND a.status = 'UNHANDLED') AS unhandledAlertCount,
g.fan_speed AS fanSpeed,
g.cpu_utilization AS cpuUtilization,
g.memory_utilization AS memoryUtilization,
g.temperature,
g.health,
g.vol_in AS volIn,
g.vol_out AS volOut
FROM equ_base b
LEFT JOIN equ_manu m ON b.manufacture = m.id
@ -259,11 +329,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
ORDER BY g.gather_time desc limit 1
</select>
<select id="selectEquMonitorByIdToList" parameterType="com.alops.system.domain.dto.EquBaseQueryDto" resultType="map"> SELECT
<select id="selectEquMonitorByIdToList" parameterType="com.alops.system.domain.dto.EquBaseQueryDto" resultType="map">
SELECT
-- 从 equ_gather 表中获取需要填充到List中的数据
g.temperature AS temperature_value,
g.vol_in AS involtage_value,
g.vol_out AS outvoltage_value,
g.memory_utilization AS memory_value,
g.cpu_utilization AS cpu_value,
g.health AS health_value,
g.gather_time AS gather_time
FROM equ_base b
@ -271,8 +343,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
LEFT JOIN equ_type t ON b.equ_type = t.id
LEFT JOIN equ_gather g ON b.id = g.equ_id
where g.cpu_utilization is not null
and b.id = #{id}
where b.id = #{id}
-- 添加时间范围约束
and g.gather_time BETWEEN #{minTime} AND #{maxTime}
@ -352,15 +423,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="name != null">name,</if>
<if test="version != null">version,</if>
<if test="ip != null">ip,</if>
<if test="manufacture != null">manufacture,</if>
<if test="equManuId != null">manufacture,</if>
<if test="location != null">location,</if>
<if test="equType != null">equ_type,</if>
<if test="equTypeId != null">equ_type,</if>
<if test="inCharge != null">in_charge,</if>
<if test="installDate != null">install_date,</if>
<if test="lifeCycle != null">life_cycle,</if>
<if test="warranty != null">warranty,</if>
<if test="createBy != null">create_by,</if>
<if test="createDate != null">create_date,</if>
<if test="equNumber != null">equ_number,</if>
status,
<if test="equImage != null">equ_image,</if>
@ -374,18 +446,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="name != null">#{name},</if>
<if test="version != null">#{version},</if>
<if test="ip != null">#{ip},</if>
<if test="manufacture != null">#{manufacture},</if>
<if test="equManuId != null">#{equManuId},</if>
<if test="location != null">#{location},</if>
<if test="equType != null">#{equType},</if>
<if test="equTypeId != null">#{equTypeId},</if>
<if test="inCharge != null">#{inCharge},</if>
<if test="installDate != null">#{installDate},</if>
<if test="lifeCycle != null">#{lifeCycle},</if>
<if test="warranty != null">#{warranty},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createDate != null">#{createDate},</if>
<if test="equNumber != null">#{equNumber},</if>
COALESCE(#{status,jdbcType=INTEGER}, 0),
<if test="equImage != null">#{equImage,jdbcType=BLOB},</if>
<if test="equImage != null">#{equImage},</if>
COALESCE(#{failureFrequency,jdbcType=BIGINT}, 0),
COALESCE(#{gatherFrequency,jdbcType=BIGINT}, 0),
<if test="deviceLevel != null">#{deviceLevel},</if>
@ -400,9 +472,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="name != null">name = #{name},</if>
<if test="version != null">version = #{version},</if>
<if test="ip != null">ip = #{ip},</if>
<if test="manufacture != null">manufacture = #{manufacture},</if>
<if test="equManuId != null">manufacture = #{equManuId},</if>
<if test="location != null">location = #{location},</if>
<if test="equType != null">equ_type = #{equType},</if>
<if test="equTypeId != null">equ_type = #{equTypeId},</if>
<if test="inCharge != null">in_charge = #{inCharge},</if>
<if test="installDate != null">install_date = #{installDate},</if>
<if test="lifeCycle != null">life_cycle = #{lifeCycle},</if>
@ -411,6 +483,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="deviceLevel != null">device_level = #{deviceLevel},</if>
<if test="supplierId != null">supplier_id = #{supplierId},</if>
<if test="equImage != null">equ_image = #{equImage},</if>
<if test="equNumber != null">equ_number = #{equNumber},</if>
</trim>
where id = #{id}
</update>

@ -32,10 +32,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<where>
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
<if test="description != null and description != ''"> and description = #{description}</if>
<if test="contactBy != null "> and contact_by = #{contactBy}</if>
<if test="contactBy != null "> and contact_by LIKE CONCAT('%', #{contactBy}, '%')</if>
<if test="contactWay != null and contactWay != ''"> and contact_way = #{contactWay}</if>
<if test="createDate != null "> and create_date = #{createDate}</if>
<if test="status != null "> and status = #{status}</if>
<if test="createBy != null "> and create_by LIKE CONCAT('%', #{createBy}, '%')</if>
</where>
</select>

@ -30,9 +30,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<where>
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
<if test="description != null and description != ''"> and description = #{description}</if>
<if test="contactBy != null and contactBy != ''"> and contact_by = #{contactBy}</if>
<if test="contactBy != null and contactBy != ''"> and contact_by LIKE CONCAT('%', #{contactBy}, '%')</if>
<if test="contactWay != null and contactWay != ''"> and contact_way = #{contactWay}</if>
<if test="status != null "> and status = #{status}</if>
<if test="createBy != null and createBy != ''"> and create_by LIKE CONCAT('%', #{createBy}, '%')</if>
</where>
</select>
@ -42,27 +43,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<insert id="insertEquSupplier" parameterType="EquSupplier">
insert into equ_supplier
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
<if test="name != null">name,</if>
<if test="description != null">description,</if>
<if test="contactBy != null">contact_by,</if>
<if test="contactWay != null">contact_way,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="status != null">status,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if>
<if test="name != null">#{name},</if>
<if test="description != null">#{description},</if>
<if test="contactBy != null">#{contactBy},</if>
<if test="contactWay != null">#{contactWay},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="status != null">#{status},</if>
</trim>
INSERT INTO equ_supplier
(id, name, description, contact_by, contact_way, create_by, create_time, status)
VALUES
(#{id}, #{name}, #{description}, #{contactBy}, #{contactWay}, #{createBy}, #{createTime}, #{status})
</insert>
<update id="updateEquSupplier" parameterType="EquSupplier">

@ -33,6 +33,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="description != null and description != ''"> and description = #{description}</if>
<if test="image != null and image != ''"> and image = #{image}</if>
<if test="createDate != null "> and create_date = #{createDate}</if>
<if test="createBy != null "> and create_by LIKE CONCAT('%', #{createBy}, '%')</if>
</where>
</select>

@ -35,7 +35,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</sql>
<sql id="selectEquVlanVoJoinGather">
select vl.id, g.equ_id, equ_gather_id, main_id, ip_address, subnet_mask, create_time, update_by, vlan_id from equ_vlan vl LEFT JOIN equ_gather g ON vl.equ_gather_id = g.id
select vl.id, g.equ_id as equId, equ_gather_id, main_id, ip_address, subnet_mask, create_time, update_by, vlan_id from equ_vlan vl LEFT JOIN equ_gather g ON vl.equ_gather_id = g.id
</sql>
<select id="selectEquVlanList" parameterType="EquVlan" resultMap="EquVlanResult">

@ -49,6 +49,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectListOne" resultMap="ScheduleRulesResult">
SELECT *
FROM schedule_rules
WHERE status = 1
</select>
<select id="selectScheduleRulesList" parameterType="ScheduleRules" resultMap="ScheduleRulesResult">
<include refid="selectScheduleRulesVo"/>
<where>

@ -6,6 +6,7 @@
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<title><%= webpackConfig.name %></title>
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
<style>

@ -0,0 +1,58 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
const api = '/device/files/'
// 查询详细
export function getDict() {
return request({
url: '/sys_dict',
method: 'get'
})
}
// 查询列表
export function list(query) {
return request({
url: api + 'list',
method: 'get',
params: query
})
}
// 查询详细
export function getInfo(id) {
return request({
url: api + '/queryById/' + parseStrEmpty(id),
method: 'get'
})
}
// 新增
export function add(data) {
return request({
url: api + 'add',
method: 'post',
data: data
})
}
// 修改
export function update(data) {
return request({
url: api + 'modify',
method: 'put',
data: data
})
}
// 删除
export function del(id) {
return request({
url: api + 'delete' + id,
method: 'delete'
})
}

@ -0,0 +1,52 @@
import request from '@/utils/request'
// 查询字典数据列表
export function listData(query) {
return request({
url: '/system/dict/data/list',
method: 'get',
params: query
})
}
// 查询字典数据详细
export function getData(dictCode) {
return request({
url: '/system/dict/data/' + dictCode,
method: 'get'
})
}
// 根据字典类型查询字典数据信息
export function getDicts(dictType) {
return request({
url: '/system/dict/data/type/' + dictType,
method: 'get'
})
}
// 新增字典数据
export function addData(data) {
return request({
url: '/system/dict/data',
method: 'post',
data: data
})
}
// 修改字典数据
export function updateData(data) {
return request({
url: '/system/dict/data',
method: 'put',
data: data
})
}
// 删除字典数据
export function delData(dictCode) {
return request({
url: '/system/dict/data/' + dictCode,
method: 'delete'
})
}

@ -0,0 +1,60 @@
import request from '@/utils/request'
// 查询字典类型列表
export function listType(query) {
return request({
url: '/system/dict/type/list',
method: 'get',
params: query
})
}
// 查询字典类型详细
export function getType(dictId) {
return request({
url: '/system/dict/type/' + dictId,
method: 'get'
})
}
// 新增字典类型
export function addType(data) {
return request({
url: '/system/dict/type',
method: 'post',
data: data
})
}
// 修改字典类型
export function updateType(data) {
return request({
url: '/system/dict/type',
method: 'put',
data: data
})
}
// 删除字典类型
export function delType(dictId) {
return request({
url: '/system/dict/type/' + dictId,
method: 'delete'
})
}
// 刷新字典缓存
export function refreshCache() {
return request({
url: '/system/dict/type/refreshCache',
method: 'delete'
})
}
// 获取字典选择框列表
export function optionselect() {
return request({
url: '/system/dict/type/optionselect',
method: 'get'
})
}

@ -0,0 +1,49 @@
import request from '@/utils/request'
const api = '/knowledge/'
// 查询详细
export function getDict() {
return request({
url: '/sys_dict',
method: 'get'
})
}
// 查询列表
export function list(query) {
return request({
url: '/knowBase/query',
method: 'get',
params: query
})
}
// 新增
export function add(data) {
return request({
url: '/knowledge/add',
method: 'post',
data: data
})
}
// 修改
export function update(data) {
return request({
url: '/knowBasemodify',
method: 'put',
data: data
})
}
// 删除
export function del(id) {
return request({
url: '/knowBase/delete/' + id,
method: 'delete'
})
}

@ -1,38 +1,20 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
const api = '/equipment/'
const api = '/device/deviceInformation/'
// 立即执行
export function protoCollect() {
export function addRule(data) {
return request({
url: api + 'protoCollect',
method: 'post'
})
}
// 定时采集规则添加
export function addTimerRule(data) {
return request({
url: api + 'addTimerRule',
url: api + 'addRule',
method: 'post',
data: data
})
}
// 查询规则
export function queryTimerRule(data) {
export function queryRule() {
return request({
url: api + 'queryTimerRule',
method: 'post',
data: data
url: api + 'queryRule',
method: 'get'
})
}
// 修改规则
export function modifyTimerRule(data) {
return request({
url: api + 'modifyTimerRule',
method: 'post',
data: data
})
}

@ -1,6 +1,5 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
const api = '/equManufacture/'
const api = '/device/deviceManu/'
// 查询详细
export function getDict() {
@ -13,7 +12,7 @@ export function getDict() {
// 查询列表
export function list(query) {
return request({
url: api + 'queryByVO',
url: api + 'query',
method: 'get',
params: query
})
@ -40,7 +39,7 @@ export function update(data) {
// 删除
export function del(id) {
return request({
url: api + 'delete' + id,
url: api + id,
method: 'delete'
})
}

@ -1,6 +1,5 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
const api = '/equipmentType/'
const api = '/device/deviceType/'
// 查询详细
export function getDict() {
@ -13,7 +12,7 @@ export function getDict() {
// 查询列表
export function list(query) {
return request({
url: api + 'queryByVO',
url: api + 'query',
method: 'get',
params: query
})
@ -40,7 +39,7 @@ export function update(data) {
// 删除
export function del(id) {
return request({
url: api + 'delete' + id,
url: api + id,
method: 'delete'
})
}

@ -14,7 +14,7 @@ export function getDict() {
export function list(query) {
return request({
url: api + 'list',
method: 'post',
method: 'get',
params: query
})
}
@ -48,7 +48,7 @@ export function update(data) {
// 删除
export function del(id) {
return request({
url: api + 'delete' + id,
url: api + id,
method: 'delete'
})
}

@ -0,0 +1,49 @@
import request from '@/utils/request'
const api = '/device/supplier/'
// 查询详细
export function getDict() {
return request({
url: '/sys_dict',
method: 'get'
})
}
// 查询列表
export function list(query) {
return request({
url: api + 'query',
method: 'get',
params: query
})
}
// 新增
export function add(data) {
return request({
url: api + 'add',
method: 'post',
data: data
})
}
// 修改
export function update(data) {
return request({
url: api + 'edit',
method: 'put',
data: data
})
}
// 删除
export function del(id) {
return request({
url: api + id,
method: 'delete'
})
}

@ -1,11 +1,11 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
const api = '/equipment/'
const api = '/device/files/'
// 查询多台设备列表
export function list(query) {
return request({
url: api + 'queryByVO',
url: api + 'list',
method: 'get',
params: query
})
@ -14,20 +14,60 @@ export function list(query) {
// 查询单台设备
export function getInfo(id) {
return request({
url: api + '/queryById/' + parseStrEmpty(id),
url: api + 'latest/' + parseStrEmpty(id),
method: 'get'
})
}
// 查询设备历史预警
// 设备管理基本信息(获取设备指定时间段内的历史监控信息)
export function historyQuery(query) {
return request({
url: '/alarm/historyQuery',
url: api + 'history',
method: 'get',
params: query
})
}
// 设备历史预警
export function alertmessage(equId) {
return request({
url: '/inMonitoring/alertmessage/' + parseStrEmpty(equId),
method: 'get'
})
}
// 查询interface接口信息
export function systemInterface(equId) {
return request({
url: '/system/interface/' + parseStrEmpty(equId),
method: 'get'
})
}
// 查询Routing路由信息
export function systemRouting(equId) {
return request({
url: '/system/routing/' + parseStrEmpty(equId),
method: 'get'
})
}
// 查询Veneer单板运行信息
export function systemVeneer(equId) {
return request({
url: '/system/veneer/' + parseStrEmpty(equId),
method: 'get'
})
}
// 查询Vlan信息
export function deviceVlan(equId) {
return request({
url: '/device/vlan/ByEquId/' + parseStrEmpty(equId),
method: 'get'
})
}
// 查询接口信息
export function interfaceQuery(query) {
return request({

@ -0,0 +1,58 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
const api = '/inMonitoring/alertMessage/'
// 查询详细
export function getDict() {
return request({
url: '/sys_dict',
method: 'get'
})
}
// 查询列表
export function list(query) {
return request({
url: api + 'list',
method: 'get',
params: query
})
}
// 查询详细
export function getInfo(id) {
return request({
url: api + '/queryById/' + parseStrEmpty(id),
method: 'get'
})
}
// 新增
export function add(data) {
return request({
url: api + 'add',
method: 'post',
data: data
})
}
// 修改
export function update(data) {
return request({
url: api + 'editAlertMessage',
method: 'put',
data: data
})
}
// 删除
export function del(id) {
return request({
url: api + id,
method: 'delete'
})
}

@ -0,0 +1,58 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
const api = '/inMonitoring/alertRule/'
// 查询详细
export function byTable() {
return request({
url: api + 'byTable',
method: 'get'
})
}
// 查询列表
export function list(query) {
return request({
url: api + 'list',
method: 'get',
params: query
})
}
// 查询详细
export function getInfo(id) {
return request({
url: api + '/queryById/' + parseStrEmpty(id),
method: 'get'
})
}
// 新增
export function add(data) {
return request({
url: api + 'addRule',
method: 'post',
data: data
})
}
// 修改
export function update(data) {
return request({
url: api + 'editRule',
method: 'put',
data: data
})
}
// 删除
export function del(id) {
return request({
url: api + id,
method: 'delete'
})
}

@ -0,0 +1,92 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
const api = '/device/files/'
// 查询详细
export function getDict() {
return request({
url: '/sys_dict',
method: 'get'
})
}
// 预警信息统
export function statistic(query) {
return request({
url: '/inMonitoring/alertMessage/statistic/list',
method: 'get',
params: query
})
}
// 统计预警信息次数
export function alertMessageTimes(query) {
return request({
url: 'inMonitoring/alertMessage/times',
method: 'get',
params: query
})
}
// 按设备类型分类统计设备信息
export function byEquType() {
return request({
url: 'device/files/byEquType',
method: 'get'
})
}
// 设备运行状态
export function listMonitor(query) {
return request({
url: 'device/files/monitorById',
method: 'get',
params: query
})
}
// 查询详细
export function getInfo(id) {
return request({
url: api + '/queryById/' + parseStrEmpty(id),
method: 'get'
})
}
// 新增
export function add(data) {
return request({
url: api + 'add',
method: 'post',
data: data
})
}
// 修改
export function update(data) {
return request({
url: api + 'modify',
method: 'put',
data: data
})
}
// 删除
export function del(id) {
return request({
url: api + id,
method: 'delete'
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 38 KiB

@ -4,7 +4,7 @@
multiple
:disabled="disabled"
:action="uploadImgUrl"
list-type="picture-card"
:list-type="listType"
:on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload"
:data="data"
@ -19,7 +19,8 @@
:on-preview="handlePictureCardPreview"
:class="{hide: this.fileList.length >= this.limit}"
>
<i class="el-icon-plus"></i>
<el-button v-if="listType == 'txt'" size="small" type="primary">点击上传</el-button>
<i class="el-icon-plus" v-else></i>
</el-upload>
<!-- 上传提示 -->
@ -57,6 +58,11 @@ export default {
type: String,
default: "/common/upload"
},
// text/picture/picture-card
listType: {
type: String,
default: "picture-card"
},
//
data: {
type: Object
@ -64,7 +70,7 @@ export default {
//
limit: {
type: Number,
default: 5
default: 1
},
// (MB)
fileSize: {
@ -195,8 +201,9 @@ export default {
},
//
handleUploadSuccess(res, file) {
console.log("%c 🍍: handleUploadSuccess -> res ", "font-size:16px;background-color:#dca159;color:white;", res)
if (res.code === 200) {
this.uploadList.push({ name: res.fileName, url: res.fileName })
this.uploadList.push({ name: res.fileName, url: res.url })
this.uploadedSuccessfully()
} else {
this.number--
@ -205,6 +212,8 @@ export default {
this.$refs.imageUpload.handleRemove(file)
this.uploadedSuccessfully()
}
console.log("%c 🇸🇰: handleUploadSuccess -> this.fileList ", "font-size:16px;background-color:#6a826e;color:white;", this.fileList)
},
//
handleDelete(file) {

@ -99,7 +99,7 @@ export const dynamicRoutes = [
permissions: ['inMonitoring:devicesState:edit'],
children: [
{
path: 'detail/:userId(\\d+)',
path: 'detail/:userId',
component: () => import('@/views/inMonitoring/devicesState/detail'),
name: 'DevicesStateDetail',
meta: { title: '设备详情', activeMenu: '/inMonitoring/devicesState-detail' }

@ -42,6 +42,7 @@ service.interceptors.request.use(config => {
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime()
}
console.log("%c 🛑: requestObj ", "font-size:16px;background-color:#4408a2;color:white;", requestObj)
const requestSize = Object.keys(JSON.stringify(requestObj)).length // 请求数据大小
const limitSize = 5 * 1024 * 1024 // 限制存放数据5M
if (requestSize >= limitSize) {

@ -52,16 +52,16 @@ export function resetForm(refName) {
}
// 添加日期范围
export function addDateRange(params, dateRange, propName) {
export function addDateRange(params, dateRange, propNameStart, propNameEnd) {
let search = params
search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {}
dateRange = Array.isArray(dateRange) ? dateRange : []
if (typeof (propName) === 'undefined') {
if (typeof (propNameStart) === 'undefined') {
search.params['beginTime'] = dateRange[0]
search.params['endTime'] = dateRange[1]
} else {
search.params['begin' + propName] = dateRange[0]
search.params['end' + propName] = dateRange[1]
search.params[propNameStart] = dateRange[0]
search.params[propNameEnd] = dateRange[1]
}
return search
}

@ -4,7 +4,7 @@
<el-card class="customer-service">
<!-- 客服头部 -->
<div class="service-header">
<h2>智能客服</h2>
<h2>AI智能助手</h2>
<p>您好我是智能助手很高兴为您服务</p>
</div>
@ -72,7 +72,7 @@ export default {
newMessage: '',
messages: [
{
text: '您好!我是智能客服,请问有什么可以帮您?',
text: '您好!我是AI智能助手,请问有什么可以帮您?',
sender: 'service',
time: this.formatTime(new Date())
}

@ -2,79 +2,31 @@
<div class="app-container">
<el-row :gutter="20">
<splitpanes :horizontal="this.$store.getters.device === 'mobile'" class="default-theme">
<!--用户数据-->
<!--知识库管理-->
<pane size="84">
<el-col>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['device:deviceInformation:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['device:deviceInformation:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['device:deviceInformation:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['device:deviceInformation:import']">导入</el-button>
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['device:deviceType:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['device:deviceInformation:export']">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
<!-- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar> -->
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
<el-table-column label="序号" align="center" key="id" prop="id"/>
<el-table-column label="文件名称" align="center" key="title" prop="title" :show-overflow-tooltip="true" />
<el-table-column label="描述" align="center" key="description" prop="description" :show-overflow-tooltip="true" />
<el-table-column label="创建人" align="center" key="createBy" prop="createBy" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createDate" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
<span>{{ parseTime(scope.row.createDate) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope" v-if="scope.row.userId !== 1">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['device:deviceInformation:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:deviceInformation:remove']">删除</el-button>
<el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['device:deviceInformation:resetPwd', 'device:deviceInformation:edit']">
<el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="handleResetPwd" icon="el-icon-key" v-hasPermi="['device:deviceInformation:resetPwd']">重置密码</el-dropdown-item>
<el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check" v-hasPermi="['device:deviceInformation:edit']">分配角色</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<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-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:deviceType:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
@ -85,67 +37,23 @@
</splitpanes>
</el-row>
<el-dialog :title="title" :visible.sync="open" width="760px" append-to-body>
<el-dialog :title="title" :visible.sync="open" width="760px" append-to-body :destroy-on-close="true">
<el-form ref="form" :model="form" :rules="rules" label-width="90px">
<el-row :gutter="20">
<!-- 用户昵称 + 手机号码 -->
<el-col :span="12">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
</el-col>
<!-- 邮箱 + 用户名称 -->
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
</el-form-item>
</el-col>
<!-- 用户密码仅新增+ 用户性别 -->
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择性别" style="width: 100%">
<el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
<el-form-item label="文档标题" prop="title">
<el-input v-model="form.title" placeholder="请输入文档标题" maxlength="30" />
</el-form-item>
</el-col>
<!-- 状态 + 角色 -->
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="角色">
<el-select v-model="form.roleIds" multiple placeholder="请选择角色" style="width: 100%">
<el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option>
</el-select>
<el-col :span="24">
<el-form-item label="文档简介" prop="description">
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入文档简介" />
</el-form-item>
</el-col>
<!-- 备注单独一行 -->
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入内容" />
<el-form-item label="上传文件" prop="fileUrl">
<ImageUpload @input="upImage" :value="form.fileUrl" :fileType="['docx','txt']" listType="txt"/>
</el-form-item>
</el-col>
</el-row>
@ -158,30 +66,11 @@
</span>
</el-dialog>
<!-- 用户导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<div class="el-upload__tip" slot="tip">
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
</div>
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user"
import { list, del, add, update } from "@/api/QandA/knowledge"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
@ -194,6 +83,7 @@ export default {
components: { Treeselect, Splitpanes, Pane },
data() {
return {
appBase:process.env.VUE_APP_BASE_API,
//
loading: true,
//
@ -206,7 +96,7 @@ export default {
showSearch: true,
//
total: 0,
//
//
userList: null,
//
title: "",
@ -232,15 +122,15 @@ export default {
children: "children",
label: "label"
},
//
//
upload: {
//
//
open: false,
//
//
title: "",
//
isUploading: false,
//
//
updateSupport: 0,
//
headers: { Authorization: "Bearer " + getToken() },
@ -251,50 +141,18 @@ export default {
queryParams: {
pageNum: 1,
pageSize: 10,
userName: undefined,
phonenumber: undefined,
status: undefined,
deptId: undefined
name: undefined
},
//
columns: [
{ key: 0, label: '用户编号', visible: true, showInSelector: true },
{ key: 1, label: '用户名称', visible: true, showInSelector: true },
{ key: 2, label: '用户昵称', visible: true, showInSelector: true },
{ key: 3, label: '部门', visible: false, showInSelector: false }, // 👈
{ key: 4, label: '手机号码', visible: true, showInSelector: true },
{ key: 5, label: '状态', visible: true, showInSelector: true },
{ key: 6, label: '创建时间', visible: true, showInSelector: true }
],
//
rules: {
userName: [
{ required: true, message: "用户名称不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
nickName: [
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
name: [
{ required: true, message: "类型名称不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '类型名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
password: [
{ required: true, message: "用户密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
image: [
{ required: true, message: "请上传设备图片", trigger: "blur" },
],
email: [
{
type: "email",
message: "请输入正确的邮箱地址",
trigger: ["blur", "change"]
}
],
phonenumber: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur"
}
]
}
}
},
@ -306,61 +164,23 @@ export default {
},
created() {
this.getList()
// this.getDeptTree()
this.getConfigKey("sys.user.initPassword").then(response => {
this.initPassword = response.msg
})
},
methods: {
/** 查询用户列表 */
/** 查询类型列表 */
getList() {
this.loading = true
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false
}
)
},
// /** */
// getDeptTree() {
// deptTreeSelect().then(response => {
// this.deptOptions = response.data
// this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
// })
// },
//
filterDisabledDept(deptList) {
return deptList.filter(dept => {
if (dept.disabled) {
return false
}
if (dept.children && dept.children.length) {
dept.children = this.filterDisabledDept(dept.children)
}
return true
})
},
//
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
//
handleNodeClick(data) {
this.queryParams.deptId = data.id
this.handleQuery()
},
//
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function() {
return changeUserStatus(row.userId, row.status)
}).then(() => {
this.$modal.msgSuccess(text + "成功")
}).catch(function() {
row.status = row.status === "0" ? "1" : "0"
})
upImage(fileList){
console.log(fileList)
this.form.fileUrl = fileList
},
//
cancel() {
@ -370,18 +190,12 @@ export default {
//
reset() {
this.form = {
userId: undefined,
deptId: undefined,
userName: undefined,
nickName: undefined,
password: undefined,
phonenumber: undefined,
email: undefined,
sex: undefined,
status: "0",
remark: undefined,
postIds: [],
roleIds: []
id: undefined,
name: undefined,
description: undefined,
createBy: undefined,
image: undefined,
createDate: undefined
}
this.resetForm("form")
},
@ -400,85 +214,35 @@ export default {
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.userId)
this.ids = selection.map(item => item.id)
this.single = selection.length != 1
this.multiple = !selection.length
},
//
handleCommand(command, row) {
switch (command) {
case "handleResetPwd":
this.handleResetPwd(row)
break
case "handleAuthRole":
this.handleAuthRole(row)
break
default:
break
}
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
getUser().then(response => {
this.postOptions = response.posts
this.roleOptions = response.roles
this.open = true
this.title = "添加用户"
this.form.password = this.initPassword
})
this.open = true
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const userId = row.userId || this.ids
getUser(userId).then(response => {
this.form = response.data
this.postOptions = response.posts
this.roleOptions = response.roles
this.$set(this.form, "postIds", response.postIds)
this.$set(this.form, "roleIds", response.roleIds)
const id = row.id || this.ids
this.open = true
this.title = "修改用户"
this.form.password = ""
})
},
/** 重置密码按钮操作 */
handleResetPwd(row) {
this.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
inputValidator: (value) => {
if (/<|>|"|'|\||\\/.test(value)) {
return "不能包含非法字符:< > \" ' \\\ |"
}
},
}).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => {})
},
/** 分配角色操作 */
handleAuthRole: function(row) {
const userId = row.userId
this.$router.push("/system/user-auth/role/" + userId)
this.title = "修改类型"
this.form = {...row, image: row.image}
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.userId != undefined) {
updateUser(this.form).then(response => {
if (this.form.id != undefined) {
update(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addUser(this.form).then(response => {
add(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
@ -489,9 +253,9 @@ export default {
},
/** 删除按钮操作 */
handleDelete(row) {
const userIds = row.userId || this.ids
this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function() {
return delUser(userIds)
const Ids = row.id || this.ids
this.$modal.confirm('是否确认删除类型编号为"' + Ids + '"的数据项?').then(function() {
return del(Ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
@ -505,7 +269,7 @@ export default {
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = "用户导入"
this.upload.title = "类型导入"
this.upload.open = true
},
/** 下载模板操作 */

@ -5,50 +5,59 @@
<!--用户数据-->
<pane size="84">
<el-col>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="auto">
<el-form :model="queryParams" :rules="rules" ref="form" size="small" :inline="true" v-show="showSearch" label-width="auto">
<el-row>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">立即执行</el-button>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="开启定时" prop="userName">
<el-radio-group v-model="radio">
<el-radio :label="1">间隔采集</el-radio>
<el-radio :label="2">固定时间采集</el-radio>
<el-form-item label="开启定时" prop="queryParams">
<el-radio-group v-model="queryParams.ruleType">
<el-radio :label="0">间隔采集</el-radio>
<el-radio :label="1">固定时间采集</el-radio>
<el-radio :label="2">立即采集</el-radio>
</el-radio-group>
</el-form-item>
</el-row>
<el-row v-show="radio == 1">
<el-row v-show="queryParams.ruleType == 0">
<el-col :span="24">
<el-form-item label="采集频率" prop="userName">
<el-input-number v-model="num" controls-position="right" @change="handleChange" :min="1"></el-input-number>
<el-form-item label="采集频率" prop="frequency">
<el-input-number v-model="queryParams.frequency" controls-position="right" :min="1"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="采集时间限制">
<el-time-picker
is-range
v-model="dateRange"
<el-form-item label="采集时间限制" prop="dateRange">
<el-date-picker
v-model="queryParams.dateRange"
@change="handleDateRangeChange"
value-format="yyyy-MM-dd hh:mm:ss"
type="daterange"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
placeholder="选择时间范围">
</el-time-picker>
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="{ disabledDate: disablePastDate }"
>
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row v-show="radio == 2">
<el-row v-show="queryParams.ruleType == 1">
<el-col :span="24">
<el-form-item label="采集时间限制">
<el-time-picker
v-model="dateRange"
<el-date-picker
v-model="queryParams.gatherTime"
:disabledDate="disablePastDate"
value-format="yyyy-MM-dd hh:mm:ss"
type="datetime"
:picker-options="{ disabledDate: disablePastDate }"
placeholder="任意时间点">
</el-time-picker>
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="submitForm">确认</el-button>
</el-form-item>
</el-row>
</el-form>
</el-col>
</pane>
@ -58,8 +67,7 @@
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user"
import { protoCollect, addTimerRule, queryTimerRule, modifyTimerRule } from "@/api/device/deviceInformation"
import { queryRule, getUser, addRule, resetUserPwd, changeUserStatus } from "@/api/device/deviceInformation"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
@ -68,7 +76,6 @@ import "splitpanes/dist/splitpanes.css"
export default {
name: "User",
dicts: ['sys_normal_disable', 'sys_user_sex'],
components: { Treeselect, Splitpanes, Pane },
data() {
return {
@ -90,62 +97,18 @@ export default {
userList: null,
//
title: "",
//
deptOptions: undefined,
//
enabledDeptOptions: undefined,
//
open: false,
//
deptName: undefined,
//
initPassword: undefined,
//
dateRange: [],
//
postOptions: [],
//
roleOptions: [],
//
form: {},
defaultProps: {
children: "children",
label: "label"
},
//
upload: {
//
open: false,
//
title: "",
//
isUploading: false,
//
updateSupport: 0,
//
headers: { Authorization: "Bearer " + getToken() },
//
url: process.env.VUE_APP_BASE_API + "/system/user/importData"
},
//
//
queryParams: {
pageNum: 1,
pageSize: 10,
userName: undefined,
phonenumber: undefined,
status: undefined,
deptId: undefined
ruleType: 0,
frequency: 1,
gatherTime: null,
startTime: null,
endTime: null,
//
dateRange: [],
},
//
columns: [
{ key: 0, label: '用户编号', visible: true, showInSelector: true },
{ key: 1, label: '用户名称', visible: true, showInSelector: true },
{ key: 2, label: '用户昵称', visible: true, showInSelector: true },
{ key: 3, label: '部门', visible: false, showInSelector: false }, // 👈
{ key: 4, label: '手机号码', visible: true, showInSelector: true },
{ key: 5, label: '状态', visible: true, showInSelector: true },
{ key: 6, label: '创建时间', visible: true, showInSelector: true }
],
//
rules: {
@ -153,28 +116,9 @@ export default {
{ required: true, message: "用户名称不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
nickName: [
dateRange: [
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
],
password: [
{ required: true, message: "用户密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
],
email: [
{
type: "email",
message: "请输入正确的邮箱地址",
trigger: ["blur", "change"]
}
],
phonenumber: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur"
}
]
}
}
},
@ -186,228 +130,44 @@ export default {
},
created() {
this.getList()
// this.getDeptTree()
this.getConfigKey("sys.user.initPassword").then(response => {
this.initPassword = response.msg
})
},
methods: {
/** 查询用户列表 */
getList() {
this.loading = true
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
queryRule().then(response => {
this.queryParams = {...this.queryParams,...response.data}
this.loading = false
}
)
},
// /** */
// getDeptTree() {
// deptTreeSelect().then(response => {
// this.deptOptions = response.data
// this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
// })
// },
//
filterDisabledDept(deptList) {
return deptList.filter(dept => {
if (dept.disabled) {
return false
}
if (dept.children && dept.children.length) {
dept.children = this.filterDisabledDept(dept.children)
}
return true
})
},
//
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
//
handleNodeClick(data) {
this.queryParams.deptId = data.id
this.handleQuery()
},
//
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function() {
return changeUserStatus(row.userId, row.status)
}).then(() => {
this.$modal.msgSuccess(text + "成功")
}).catch(function() {
row.status = row.status === "0" ? "1" : "0"
})
},
//
cancel() {
this.open = false
this.reset()
},
//
reset() {
this.form = {
userId: undefined,
deptId: undefined,
userName: undefined,
nickName: undefined,
password: undefined,
phonenumber: undefined,
email: undefined,
sex: undefined,
status: "0",
remark: undefined,
postIds: [],
roleIds: []
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = []
this.resetForm("queryForm")
this.queryParams.deptId = undefined
this.$refs.tree.setCurrentKey(null)
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.userId)
this.single = selection.length != 1
this.multiple = !selection.length
},
//
handleCommand(command, row) {
switch (command) {
case "handleResetPwd":
this.handleResetPwd(row)
break
case "handleAuthRole":
this.handleAuthRole(row)
break
default:
break
}
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
getUser().then(response => {
this.postOptions = response.posts
this.roleOptions = response.roles
this.open = true
this.title = "添加用户"
this.form.password = this.initPassword
})
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const userId = row.userId || this.ids
getUser(userId).then(response => {
this.form = response.data
this.postOptions = response.posts
this.roleOptions = response.roles
this.$set(this.form, "postIds", response.postIds)
this.$set(this.form, "roleIds", response.roleIds)
this.open = true
this.title = "修改用户"
this.form.password = ""
})
},
/** 重置密码按钮操作 */
handleResetPwd(row) {
this.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
inputValidator: (value) => {
if (/<|>|"|'|\||\\/.test(value)) {
return "不能包含非法字符:< > \" ' \\\ |"
}
},
}).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => {})
},
/** 分配角色操作 */
handleAuthRole: function(row) {
const userId = row.userId
this.$router.push("/system/user-auth/role/" + userId)
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.userId != undefined) {
updateUser(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addUser(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
addRule(this.queryParams).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const userIds = row.userId || this.ids
this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function() {
return delUser(userIds)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('system/user/export', {
...this.queryParams
}, `user_${new Date().getTime()}.xlsx`)
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = "用户导入"
this.upload.open = true
},
/** 下载模板操作 */
importTemplate() {
this.download('system/user/importTemplate', {
}, `user_template_${new Date().getTime()}.xlsx`)
},
//
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true
},
//
handleFileSuccess(response, file, fileList) {
this.upload.open = false
this.upload.isUploading = false
this.$refs.upload.clearFiles()
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
this.getList()
},
//
submitFileForm() {
this.$refs.upload.submit()
handleDateRangeChange(value) {
console.log("%c 🐁: handleDateRangeChange -> value ", "font-size:16px;background-color:#dbe986;color:black;", value)
this.queryParams.startTime = value[0]
this.queryParams.endTime = value[1]
},
disablePastDate(time) {
//
const today = new Date();
// 00:00:00
today.setHours(0, 0, 0, 0);
// 00:00:00
console.log("%c 🐇: disablePastDate -> time.getTime() < today.getTime() ", "font-size:16px;background-color:#c5c908;color:black;", time.getTime() , today.getTime(), time.getTime() < today.getTime())
return time.getTime() < today.getTime();
}
}
}

@ -12,9 +12,6 @@
<el-form-item label="联系人" prop="contactBy">
<el-input v-model="queryParams.contactBy" placeholder="请输入联系人" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="联系电话" prop="contactWay">
<el-input v-model="queryParams.contactWay" placeholder="请输入联系电话" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@ -25,7 +22,7 @@
<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-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-col>
<el-col :span="1.5">
@ -33,22 +30,31 @@
</el-col>
<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-col>
</el-col> -->
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="ID" align="center" key="Id" prop="Id" />
<el-table-column
label="序号"
width="60"
type="index"
></el-table-column>
<el-table-column label="厂商名称" align="center" key="name" prop="name" width="120" />
<el-table-column label="联系人" align="center" key="contactBy" prop="contactBy" width="120" />
<el-table-column label="联系方式" align="center" key="contactWay" prop="contactWay" width="120" />
<el-table-column label="创建人" align="center" key="CreateBy" prop="CreateBy" width="120" />
<el-table-column label="描述" align="center" key="description" prop="description" width="120" />
<el-table-column label="创建人" align="center" key="createBy" prop="createBy" width="120" />
<el-table-column label="创建日期" align="center" prop="CreateDate" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.CreateDate) }}</span>
<span>{{ parseTime(scope.row.createDate) }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" key="status" prop="status" width="120" >
<template slot-scope="scope">
<dict-tag :options="dict.type.device_disable" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="状态" align="center" key="Status" prop="Status" width="120" />
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<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>
@ -68,12 +74,12 @@
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="厂商名称" prop="name">
<el-input v-model="form.name" placeholder="请输入用户昵称" maxlength="30" />
<el-input v-model="form.name" placeholder="请输入联系人" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系人" prop="contactBy">
<el-input v-model="form.contactBy" placeholder="请输入手机号码" maxlength="30" />
<el-input v-model="form.contactBy" placeholder="请输入联系人" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
@ -81,6 +87,18 @@
<el-input v-model="form.contactWay" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态" prop="status">
<el-select v-model="form.status" placeholder="启用状态" clearable>
<el-option v-for="dict in statusSelections" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="描述" prop="description">
<el-input v-model="form.description" placeholder="请输入描述" type="textarea" :rows="3" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
@ -112,7 +130,7 @@
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user"
import { list, del, add, update, resetUserPwd, changeUserStatus } from "@/api/device/deviceManufacturer"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
@ -121,7 +139,7 @@ import "splitpanes/dist/splitpanes.css"
export default {
name: "User",
dicts: ['sys_normal_disable', 'sys_user_sex'],
dicts: ['sys_normal_disable', 'sys_user_sex','device_disable'],
components: { Treeselect, Splitpanes, Pane },
data() {
return {
@ -163,6 +181,11 @@ export default {
children: "children",
label: "label"
},
statusSelections: [
{ label: "正常", value: 1 },
{ label: "停用", value: 0 }
],
//
upload: {
//
@ -183,38 +206,28 @@ export default {
pageNum: 1,
pageSize: 10,
name: undefined,
contactBy: undefined,
status: undefined,
deptId: undefined
contactBy: undefined
},
//
rules: {
name: [
{ required: true, message: "用户名称不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
nickName: [
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
],
password: [
{ required: true, message: "用户密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
],
email: [
{
type: "email",
message: "请输入正确的邮箱地址",
trigger: ["blur", "change"]
}
{ required: true, message: "厂商名称不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '厂商名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
contactBy: [
{ required: true, message: "联系人不能为空", trigger: "blur" }
],
contactWay: [
{ required: true, message: "联系方式不能为空", trigger: "blur" },
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur"
}
]
],
status: [
{ required: true, message: "状态不能为空", trigger: "blur" }
],
}
}
},
@ -226,16 +239,12 @@ export default {
},
created() {
this.getList()
// this.getDeptTree()
this.getConfigKey("sys.user.initPassword").then(response => {
this.initPassword = response.msg
})
},
methods: {
/** 查询用户列表 */
getList() {
this.loading = true
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false
@ -275,7 +284,7 @@ export default {
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
this.$modal.confirm('确认要"' + text + '""' + row.name + '"用户吗?').then(function() {
return changeUserStatus(row.Id, row.status)
return changeUserStatus(row.id, row.status)
}).then(() => {
this.$modal.msgSuccess(text + "成功")
}).catch(function() {
@ -290,7 +299,7 @@ export default {
//
reset() {
this.form = {
Id: undefined,
id: undefined,
deptId: undefined,
name: undefined,
nickName: undefined,
@ -298,7 +307,7 @@ export default {
contactBy: undefined,
email: undefined,
sex: undefined,
status: "0",
status: undefined,
remark: undefined,
postIds: [],
roleIds: []
@ -314,13 +323,11 @@ export default {
resetQuery() {
this.dateRange = []
this.resetForm("queryForm")
this.queryParams.deptId = undefined
this.$refs.tree.setCurrentKey(null)
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.Id)
this.ids = selection.map(item => item.id)
this.single = selection.length != 1
this.multiple = !selection.length
},
@ -340,28 +347,15 @@ export default {
/** 新增按钮操作 */
handleAdd() {
this.reset()
getUser().then(response => {
this.postOptions = response.posts
this.roleOptions = response.roles
this.open = true
this.title = "添加用户"
this.form.password = this.initPassword
})
this.open = true
this.title = "添加厂商"
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const Id = row.Id || this.ids
getUser(Id).then(response => {
this.form = response.data
this.postOptions = response.posts
this.roleOptions = response.roles
this.$set(this.form, "postIds", response.postIds)
this.$set(this.form, "roleIds", response.roleIds)
this.open = true
this.title = "修改用户"
this.form.password = ""
})
this.form = {...row}
this.open = true
this.title = "修改厂商"
},
/** 重置密码按钮操作 */
handleResetPwd(row) {
@ -377,28 +371,28 @@ export default {
}
},
}).then(({ value }) => {
resetUserPwd(row.Id, value).then(response => {
resetUserPwd(row.id, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => {})
},
/** 分配角色操作 */
handleAuthRole: function(row) {
const Id = row.Id
this.$router.push("/system/user-auth/role/" + Id)
const id = row.id
this.$router.push("/system/user-auth/role/" + id)
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.Id != undefined) {
updateUser(this.form).then(response => {
if (this.form.id != undefined) {
update(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addUser(this.form).then(response => {
add(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
@ -409,9 +403,9 @@ export default {
},
/** 删除按钮操作 */
handleDelete(row) {
const Ids = row.Id || this.ids
const Ids = row.id || this.ids
this.$modal.confirm('是否确认删除用户编号为"' + Ids + '"的数据项?').then(function() {
return delUser(Ids)
return del(Ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")

@ -221,10 +221,6 @@ export default {
},
created() {
this.getList()
// this.getDeptTree()
this.getConfigKey("sys.user.initPassword").then(response => {
this.initPassword = response.msg
})
},
methods: {
/** 查询用户列表 */

@ -11,14 +11,6 @@
<el-form-item label="类型名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入类型名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<!-- <el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="类型状态" clearable style="width: 240px">
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item> -->
<el-form-item label="创建时间">
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@ -29,21 +21,17 @@
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['device:deviceType:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['device:deviceType:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['device:deviceType:import']">导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['device:deviceType:export']">导出</el-button>
</el-col>
<!-- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar> -->
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="类型编号" align="center" key="Id" prop="Id"/>
<el-table-column
label="序号"
width="60"
type="index"
></el-table-column>
<el-table-column label="类型编号" align="center" key="id" prop="id"/>
<el-table-column label="设备类型名称" align="center" key="name" prop="name" :show-overflow-tooltip="true" />
<el-table-column label="描述" align="center" key="description" prop="description" :show-overflow-tooltip="true" />
<el-table-column label="图片" align="center" key="image" prop="image" :show-overflow-tooltip="true" >
@ -51,14 +39,14 @@
<ImagePreview :src="scope.row.image"/>
</template>
</el-table-column>
<el-table-column label="创建人" align="center" key="CreateBy" prop="CreateBy" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
<el-table-column label="创建人" align="center" key="createBy" prop="createBy" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createDate" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
<span>{{ parseTime(scope.row.createDate) }}</span>
</template>
</el-table-column>
<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-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:deviceType:remove']">删除</el-button>
</template>
@ -71,24 +59,23 @@
</splitpanes>
</el-row>
<el-dialog :title="title" :visible.sync="open" width="760px" append-to-body>
<el-dialog :title="title" :visible.sync="open" width="760px" append-to-body :destroy-on-close="true">
<el-form ref="form" :model="form" :rules="rules" label-width="90px">
<el-row :gutter="20">
<!-- 类型昵称 + 手机号码 -->
<el-col :span="12">
<el-form-item label="设备名称" prop="name">
<el-input v-model="form.name" placeholder="请输入类型昵称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备图片" prop="phonenumber">
<ImageUpload/>
<el-col :span="24">
<el-form-item label="设备图片" prop="image">
<ImageUpload @input="upImage" :value="form.image"/>
</el-form-item>
</el-col>
<!-- 备注单独一行 -->
<el-col :span="24">
<el-form-item label="描述">
<el-form-item label="介绍">
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入内容" />
</el-form-item>
</el-col>
@ -102,30 +89,11 @@
</span>
</el-dialog>
<!-- 类型导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<div class="el-upload__tip" slot="tip">
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的类型数据
</div>
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user"
import { list, del, add, update } from "@/api/device/deviceType"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
@ -138,6 +106,7 @@ export default {
components: { Treeselect, Splitpanes, Pane },
data() {
return {
appBase:process.env.VUE_APP_BASE_API,
//
loading: true,
//
@ -195,21 +164,8 @@ export default {
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined,
phonenumber: undefined,
status: undefined,
deptId: undefined
name: undefined
},
//
columns: [
{ key: 0, label: '类型编号', visible: true, showInSelector: true },
{ key: 1, label: '类型名称', visible: true, showInSelector: true },
{ key: 2, label: '类型昵称', visible: true, showInSelector: true },
{ key: 3, label: '部门', visible: false, showInSelector: false }, // 👈
{ key: 4, label: '手机号码', visible: true, showInSelector: true },
{ key: 5, label: '状态', visible: true, showInSelector: true },
{ key: 6, label: '创建时间', visible: true, showInSelector: true }
],
//
rules: {
@ -217,28 +173,9 @@ export default {
{ required: true, message: "类型名称不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '类型名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
name: [
{ required: true, message: "类型昵称不能为空", trigger: "blur" }
],
password: [
{ required: true, message: "类型密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '类型密码长度必须介于 5 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
image: [
{ required: true, message: "请上传设备图片", trigger: "blur" },
],
email: [
{
type: "email",
message: "请输入正确的邮箱地址",
trigger: ["blur", "change"]
}
],
phonenumber: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur"
}
]
}
}
},
@ -250,61 +187,21 @@ export default {
},
created() {
this.getList()
// this.getDeptTree()
this.getConfigKey("sys.user.initPassword").then(response => {
this.initPassword = response.msg
})
},
methods: {
/** 查询类型列表 */
getList() {
this.loading = true
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false
}
)
},
// /** */
// getDeptTree() {
// deptTreeSelect().then(response => {
// this.deptOptions = response.data
// this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
// })
// },
//
filterDisabledDept(deptList) {
return deptList.filter(dept => {
if (dept.disabled) {
return false
}
if (dept.children && dept.children.length) {
dept.children = this.filterDisabledDept(dept.children)
}
return true
})
},
//
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
//
handleNodeClick(data) {
this.queryParams.deptId = data.id
this.handleQuery()
},
//
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
this.$modal.confirm('确认要"' + text + '""' + row.name + '"类型吗?').then(function() {
return changeUserStatus(row.Id, row.status)
}).then(() => {
this.$modal.msgSuccess(text + "成功")
}).catch(function() {
row.status = row.status === "0" ? "1" : "0"
})
upImage(fileList){
console.log(fileList)
this.form.image = fileList
},
//
cancel() {
@ -314,18 +211,12 @@ export default {
//
reset() {
this.form = {
Id: undefined,
deptId: undefined,
name: undefined,
id: undefined,
name: undefined,
password: undefined,
phonenumber: undefined,
email: undefined,
sex: undefined,
status: "0",
description: undefined,
postIds: [],
roleIds: []
createBy: undefined,
image: undefined,
createDate: undefined
}
this.resetForm("form")
},
@ -336,93 +227,40 @@ export default {
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = []
this.resetForm("queryForm")
this.queryParams.deptId = undefined
this.$refs.tree.setCurrentKey(null)
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.Id)
this.ids = selection.map(item => item.id)
this.single = selection.length != 1
this.multiple = !selection.length
},
//
handleCommand(command, row) {
switch (command) {
case "handleResetPwd":
this.handleResetPwd(row)
break
case "handleAuthRole":
this.handleAuthRole(row)
break
default:
break
}
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
getUser().then(response => {
this.postOptions = response.posts
this.roleOptions = response.roles
this.open = true
this.title = "添加类型"
this.form.password = this.initPassword
})
this.open = true
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const Id = row.Id || this.ids
getUser(Id).then(response => {
this.form = response.data
this.postOptions = response.posts
this.roleOptions = response.roles
this.$set(this.form, "postIds", response.postIds)
this.$set(this.form, "roleIds", response.roleIds)
const id = row.id || this.ids
this.open = true
this.title = "修改类型"
this.form.password = ""
})
},
/** 重置密码按钮操作 */
handleResetPwd(row) {
this.$prompt('请输入"' + row.name + '"的新密码', "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "类型密码长度必须介于 5 和 20 之间",
inputValidator: (value) => {
if (/<|>|"|'|\||\\/.test(value)) {
return "不能包含非法字符:< > \" ' \\\ |"
}
},
}).then(({ value }) => {
resetUserPwd(row.Id, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => {})
},
/** 分配角色操作 */
handleAuthRole: function(row) {
const Id = row.Id
this.$router.push("/system/user-auth/role/" + Id)
this.form = {...row, image: row.image}
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.Id != undefined) {
updateUser(this.form).then(response => {
if (this.form.id != undefined) {
update(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addUser(this.form).then(response => {
add(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
@ -433,9 +271,9 @@ export default {
},
/** 删除按钮操作 */
handleDelete(row) {
const Ids = row.Id || this.ids
const Ids = row.id || this.ids
this.$modal.confirm('是否确认删除类型编号为"' + Ids + '"的数据项?').then(function() {
return delUser(Ids)
return del(Ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")

@ -6,27 +6,19 @@
<pane size="84">
<el-col>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="设备名称" prop="Name">
<el-input v-model="queryParams.Name" placeholder="请输入设备名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="安装位置" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入安装位置" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="设备类型" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入设备类型" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="安装日期">
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" 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 label="设备名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入设备名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="启用状态" clearable style="width: 240px">
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
<el-option v-for="dict in dict.type.device_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="设备级别" prop="status">
<el-select v-model="queryParams.status" placeholder="设备级别" clearable style="width: 240px">
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
<el-form-item label="安装位置" prop="location">
<el-input v-model="queryParams.phonenumber" placeholder="请输入安装位置" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
@ -41,53 +33,55 @@
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['device:files:remove']">删除</el-button>
</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:files:import']">导入</el-button>
</el-col>
</el-col> -->
</el-row>
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="设备编号" align="center" key="Id" prop="Id" />
<el-table-column label="设备名称" align="center" key="Name" prop="Name" :show-overflow-tooltip="true" />
<el-table-column label="设备版本" align="center" key="Version" prop="Version" :show-overflow-tooltip="true" />
<el-table-column label="设备类型" align="center" key="EquType" prop="EquType" :show-overflow-tooltip="true" />
<el-table-column label="设备级别" align="center" prop="phonenumber" width="120" />
<el-table-column
label="序号"
width="60"
type="index"
></el-table-column>
<el-table-column label="设备ID" align="center" key="equNumber" prop="equNumber" />
<el-table-column label="设备名称" align="center" key="name" prop="name" :show-overflow-tooltip="true" />
<el-table-column label="设备版本" align="center" key="version" prop="version" :show-overflow-tooltip="true" />
<el-table-column label="设备类型" align="center" key="equType" prop="equType" :show-overflow-tooltip="true" />
<el-table-column label="设备级别" align="center" key="deviceLevel" prop="deviceLevel" width="120" />
<el-table-column label="启用状态" align="center" key="status">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
<dict-tag :options="dict.type.device_disable" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="带外管理IP" align="center" key="Ip" prop="Ip" width="120" />
<el-table-column label="设备厂商" align="center" key="Manufacture" prop="Manufacture" width="120" />
<el-table-column label="安装位置" align="center" key="Location" prop="Location" width="120" />
<el-table-column label="安装时间" align="center" prop="InstallDate" width="160">
<el-table-column label="带外管理IP" align="center" key="ip" prop="ip" width="120" />
<el-table-column label="安装位置" align="center" key="location" prop="Location" width="120" />
<el-table-column label="安装时间" align="center" prop="installDate" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.InstallDate) }}</span>
<span>{{ parseTime(scope.row.installDate) }}</span>
</template>
</el-table-column>
<el-table-column label="设备管理员" align="center" prop="phonenumber" width="120" />
<el-table-column label="预计年限" align="center" key="LifeCycle" prop="LifeCycle" width="120" />
<el-table-column label="服役年限" align="center" key="ServiceTime" prop="ServiceTime" width="120" />
<el-table-column label="设备厂商" align="center" key="manufacture" prop="manufacture" width="120" />
<el-table-column label="设备供应商" align="center" key="supplierName" prop="supplierName" width="120" />
<el-table-column label="设备管理员" align="center" key="inCharge" prop="inCharge" width="120" />
<el-table-column label="预计年限" align="center" key="lifeCycle" prop="lifeCycle" width="120" />
<el-table-column label="服役年限" align="center" key="serviceTime" prop="serviceTime" width="120" />
<el-table-column label="质保时间" align="center" key="warranty" prop="warranty" width="120" />
<el-table-column label="累计预警次数" align="center" key="FailureFrequency" prop="FailureFrequency" width="120" />
<el-table-column label="累计维修次数" align="center" key="RepairFrequency" prop="RepairFrequency" width="120" />
<el-table-column label="累计维修金额" align="center" key="RepairCost" prop="RepairCost" width="120" />
<el-table-column label="设备添加人" align="center" key="CreateBy" prop="CreateBy" width="120" />
<el-table-column label="添加时间" align="center" prop="CreateDate" width="160">
<el-table-column label="设备图片" align="center" key="image" prop="image" :show-overflow-tooltip="true" >
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
<ImagePreview :src="scope.row.image"/>
</template>
</el-table-column>
<el-table-column label="修改人" align="center" prop="UpdateBy" width="120" />
<el-table-column label="修改时间" align="center" prop="createTime" width="160">
<el-table-column label="设备添加人" align="center" key="createBy" prop="createBy" width="120" />
<el-table-column label="添加日期" align="center" prop="createDate" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
<span>{{ parseTime(scope.row.createDate) }}</span>
</template>
</el-table-column>
<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">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['device:files:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:files:remove']">删除</el-button>
</template>
@ -104,70 +98,71 @@
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="设备编号" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入设备编号" maxlength="30" />
<el-form-item label="设备编号" prop="equNumber">
<el-input v-model="form.equNumber" placeholder="请输入设备名称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备名称" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入设备名称" maxlength="30" />
<el-form-item label="设备名称" prop="name">
<el-input v-model="form.name" placeholder="请输入设备名称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备版本" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入设备版本" maxlength="30" />
<el-form-item label="设备版本" prop="version">
<el-input v-model="form.version" placeholder="请输入设备版本" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备类型" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入设备类型" maxlength="30" />
<el-form-item label="设备类型" prop="equType">
<el-input v-model="form.equType" placeholder="请输入设备类型" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备级别" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入设备级别" maxlength="30" />
<el-form-item label="设备级别" prop="deviceLevel">
<el-select v-model="form.deviceLevel" 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-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="带外管理IP" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入带外管理IP" maxlength="30" />
<el-form-item label="带外管理IP" prop="ip">
<el-input v-model="form.ip" placeholder="请输入带外管理IP" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备厂商" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入设备厂商" maxlength="30" />
<el-form-item label="设备厂商" prop="manufacture">
<el-input v-model="form.manufacture" placeholder="请输入设备厂商" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="安装位置" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入安装位置" maxlength="30" />
<el-form-item label="安装位置" prop="location">
<el-input v-model="form.location" placeholder="请输入安装位置" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备管理员" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入设备管理员" maxlength="30" />
<el-form-item label="设备管理员" prop="inCharge">
<el-input v-model="form.inCharge" placeholder="请输入设备管理员" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预计年限" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入预计年限" maxlength="30" />
<el-form-item label="预计年限" prop="lifeCycle">
<el-input v-model="form.lifeCycle" placeholder="请输入预计年限" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="服役年限" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入服役年限" maxlength="30" />
<el-form-item label="服役年限" prop="serviceTime">
<el-input v-model="form.serviceTime" placeholder="请输入服役年限" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="质保年限" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入质保年限" maxlength="30" />
<el-form-item label="质保年限" prop="warranty">
<el-input v-model="form.warranty" placeholder="请输入质保年限" maxlength="30" />
</el-form-item>
</el-col>
<!-- 备注单独一行 -->
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入内容" />
<el-form-item label="设备图片" prop="image">
<ImageUpload @input="upImage" :value="form.image"/>
</el-form-item>
</el-col>
</el-row>
@ -212,7 +207,7 @@ import "splitpanes/dist/splitpanes.css"
export default {
name: "User",
dicts: ['sys_normal_disable', 'sys_user_sex'],
dicts: ['device_disable', 'sys_user_sex', 'warning_level'],
components: { Treeselect, Splitpanes, Pane },
data() {
return {
@ -273,31 +268,50 @@ export default {
queryParams: {
pageNum: 1,
pageSize: 10,
Name: undefined,
phonenumber: undefined,
status: undefined,
deptId: undefined
name: undefined,
status: undefined
},
//
columns: [
{ key: 0, label: '设备编号', visible: true, showInSelector: true },
{ key: 1, label: '设备名称', visible: true, showInSelector: true },
{ key: 2, label: '设备级别', visible: true, showInSelector: true },
{ key: 3, label: '部门', visible: false, showInSelector: false }, // 👈
{ key: 4, label: '手机号码', visible: true, showInSelector: true },
{ key: 5, label: '状态', visible: true, showInSelector: true },
{ key: 6, label: '创建时间', visible: true, showInSelector: true }
],
//
rules: {
Name: [
{ required: true, message: "设备名称不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '设备名称长度必须介于 2 和 20 之间', trigger: 'blur' }
equNumber: [
{ required: true, message: "设备编号不能为空", trigger: "blur" },
],
name: [
{ required: true, message: "设备名称不能为空", trigger: "blur" }
],
version: [
{ required: true, message: "设备版本不能为空", trigger: "blur" },
],
equType: [
{ required: true, message: "设备类型不能为空", trigger: "blur" }
],
deviceLevel: [
{ required: true, message: "设备级别不能为空", trigger: "blur" },
],
ip: [
{ required: true, message: "带外管理IP不能为空", trigger: "blur" }
],
manufacture: [
{ required: true, message: "设备厂商不能为空", trigger: "blur" },
],
location: [
{ required: true, message: "安装位置不能为空", trigger: "blur" }
],
inCharge: [
{ required: true, message: "设备管理员不能为空", trigger: "blur" },
],
lifeCycle: [
{ required: true, message: "预计年限不能为空", trigger: "blur" }
],
serviceTime: [
{ required: true, message: "服役年限不能为空", trigger: "blur" },
],
warranty: [
{ required: true, message: "质保年限不能为空", trigger: "blur" }
],
image: [
{ required: true, message: "设备图片不能为空", trigger: "blur" }
],
nickName: [
{ required: true, message: "设备昵称不能为空", trigger: "blur" }
]
}
}
},
@ -309,68 +323,21 @@ export default {
},
created() {
this.getList()
// this.getDeptTree()
this.getConfigKey("sys.user.initPassword").then(response => {
this.initPassword = response.msg
})
},
methods: {
/** 查询设备列表 */
getDicts() {
getDict().then(response => {
console.log("%c 🗝: getDict -> response ", "font-size:16px;background-color:#796b0d;color:white;", response)
}
)
},
/** 查询设备列表 */
getList() {
this.loading = true
list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
list({minTime:this.dateRange[0],maxTime:this.dateRange[1],...this.queryParams}).then(response => {
this.dataList = response.rows
this.total = response.total
this.loading = false
}
)
},
// /** */
// getDeptTree() {
// deptTreeSelect().then(response => {
// this.deptOptions = response.data
// this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
// })
// },
//
filterDisabledDept(deptList) {
return deptList.filter(dept => {
if (dept.disabled) {
return false
}
if (dept.children && dept.children.length) {
dept.children = this.filterDisabledDept(dept.children)
}
return true
})
},
//
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
//
handleNodeClick(data) {
this.queryParams.deptId = data.id
this.handleQuery()
},
//
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
this.$modal.confirm('确认要"' + text + '""' + row.Name + '"设备吗?').then(function() {
return changeUserStatus(row.Id, row.status)
}).then(() => {
this.$modal.msgSuccess(text + "成功")
}).catch(function() {
row.status = row.status === "0" ? "1" : "0"
})
upImage(fileList){
console.log(fileList)
this.form.image = fileList
},
//
cancel() {
@ -380,9 +347,9 @@ export default {
//
reset() {
this.form = {
Id: undefined,
id: undefined,
deptId: undefined,
Name: undefined,
name: undefined,
nickName: undefined,
password: undefined,
phonenumber: undefined,
@ -403,67 +370,33 @@ export default {
/** 重置按钮操作 */
resetQuery() {
this.dateRange = []
// this.resetForm("queryForm")
// this.queryParams.deptId = undefined
// this.$refs.tree.setCurrentKey(null)
// this.handleQuery()
this.getDicts()
this.resetForm("queryForm")
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.Id)
this.ids = selection.map(item => item.id)
this.single = selection.length != 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
// getInfo().then(response => {
// this.postOptions = response.posts
// this.roleOptions = response.roles
// })
this.open = true
this.title = "添加设备"
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const Id = row.Id || this.ids
getInfo(Id).then(response => {
this.form = response.data
this.postOptions = response.posts
this.roleOptions = response.roles
this.$set(this.form, "postIds", response.postIds)
this.$set(this.form, "roleIds", response.roleIds)
this.open = true
this.title = "修改设备"
this.form.password = ""
})
},
/** 重置密码按钮操作 */
handleResetPwd(row) {
this.$prompt('请输入"' + row.Name + '"的新密码', "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "设备密码长度必须介于 5 和 20 之间",
inputValidator: (value) => {
if (/<|>|"|'|\||\\/.test(value)) {
return "不能包含非法字符:< > \" ' \\\ |"
}
},
}).then(({ value }) => {
resetUserPwd(row.Id, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => {})
this.form = {...row}
this.open = true
this.title = "修改"
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.Id != undefined) {
if (this.form.id != undefined) {
update(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
@ -481,20 +414,14 @@ export default {
},
/** 删除按钮操作 */
handleDelete(row) {
const Ids = row.Id || this.ids
this.$modal.confirm('是否确认删除设备编号为"' + Ids + '"的数据项?').then(function() {
const Ids = row.id || this.ids
this.$modal.confirm('是否确认删除设备ID为"' + Ids + '"的数据项?').then(function() {
return del(Ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('system/user/export', {
...this.queryParams
}, `user_${new Date().getTime()}.xlsx`)
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = "设备导入"

@ -0,0 +1,348 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<splitpanes :horizontal="this.$store.getters.device === 'mobile'" class="default-theme">
<!--类型类型管理-->
<pane size="84">
<el-col>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="类型名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入类型名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['device:deviceType:add']">新增</el-button>
</el-col>
<!-- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar> -->
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column
label="序号"
width="60"
type="index"
></el-table-column>
<el-table-column label="供应商名称" align="center" key="name" prop="name" width="160" :show-overflow-tooltip="true" />
<el-table-column label="联系人" align="center" key="contactBy" prop="contactBy" width="120" />
<el-table-column label="联系方式" align="center" key="contactWay" prop="contactWay" width="120" />
<el-table-column label="描述" align="center" key="description" prop="description" width="120" />
<el-table-column label="创建人" align="center" key="createBy" prop="createBy" width="120" />
<el-table-column label="创建日期" align="center" prop="createTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" key="status" prop="status" width="120" >
<template slot-scope="scope">
<span>{{ scope.row.status ? '正常' : '停用' }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<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-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:deviceType:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
</el-col>
</pane>
</splitpanes>
</el-row>
<el-dialog :title="title" :visible.sync="open" width="760px" append-to-body :destroy-on-close="true">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="供应商名称" prop="name">
<el-input v-model="form.name" placeholder="请输入联系人" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系人" prop="contactBy">
<el-input v-model="form.contactBy" placeholder="请输入联系人" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系方式" prop="contactWay">
<el-input v-model="form.contactWay" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态" prop="status">
<el-select v-model="form.status" placeholder="启用状态" clearable>
<el-option v-for="dict in statusSelections" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="描述" prop="description">
<el-input v-model="form.description" placeholder="请输入描述" type="textarea" :rows="3" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { list, del, add, update } from "@/api/device/supplier"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import { Splitpanes, Pane } from "splitpanes"
import "splitpanes/dist/splitpanes.css"
export default {
name: "User",
dicts: ['sys_normal_disable', 'sys_user_sex'],
components: { Treeselect, Splitpanes, Pane },
data() {
return {
appBase:process.env.VUE_APP_BASE_API,
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
userList: null,
//
title: "",
//
deptOptions: undefined,
//
enabledDeptOptions: undefined,
//
open: false,
//
deptName: undefined,
//
initPassword: undefined,
//
dateRange: [],
//
postOptions: [],
//
roleOptions: [],
//
form: {},
statusSelections: [
{ label: "正常", value: 1 },
{ label: "停用", value: 0 }
],
defaultProps: {
children: "children",
label: "label"
},
//
upload: {
//
open: false,
//
title: "",
//
isUploading: false,
//
updateSupport: 0,
//
headers: { Authorization: "Bearer " + getToken() },
//
url: process.env.VUE_APP_BASE_API + "/system/user/importData"
},
//
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined
},
//
rules: {
name: [
{ required: true, message: "供应商名称不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '供应商名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
contactBy: [
{ required: true, message: "联系人不能为空", trigger: "blur" }
],
contactWay: [
{ required: true, message: "联系方式不能为空", trigger: "blur" },
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur"
}
],
status: [
{ required: true, message: "状态不能为空", trigger: "blur" }
],
}
}
},
watch: {
//
deptName(val) {
this.$refs.tree.filter(val)
}
},
created() {
this.getList()
},
methods: {
/** 查询类型列表 */
getList() {
this.loading = true
list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false
}
)
},
upImage(fileList){
console.log(fileList)
this.form.image = fileList
},
//
cancel() {
this.open = false
this.reset()
},
//
reset() {
this.form = {
id: undefined,
name: undefined,
description: undefined,
createBy: undefined,
image: undefined,
createDate: undefined
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = []
this.resetForm("queryForm")
this.queryParams.deptId = undefined
this.$refs.tree.setCurrentKey(null)
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length != 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const id = row.id || this.ids
this.open = true
this.title = "修改类型"
this.form = {...row, image: row.image}
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != undefined) {
update(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
add(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const Ids = row.id || this.ids
this.$modal.confirm('是否确认删除类型编号为"' + Ids + '"的数据项?').then(function() {
return del(Ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('system/user/export', {
...this.queryParams
}, `user_${new Date().getTime()}.xlsx`)
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = "类型导入"
this.upload.open = true
},
/** 下载模板操作 */
importTemplate() {
this.download('system/user/importTemplate', {
}, `user_template_${new Date().getTime()}.xlsx`)
},
//
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true
},
//
handleFileSuccess(response, file, fileList) {
this.upload.open = false
this.upload.isUploading = false
this.$refs.upload.clearFiles()
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
this.getList()
},
//
submitFileForm() {
this.$refs.upload.submit()
}
}
}
</script>

@ -306,10 +306,6 @@ export default {
},
created() {
this.getList()
// this.getDeptTree()
this.getConfigKey("sys.user.initPassword").then(response => {
this.initPassword = response.msg
})
},
methods: {
/** 查询用户列表 */

@ -1,75 +1,485 @@
<template>
<div class="">
<h3 class="h3" @click="handleDetail">交换机</h3>
<el-row>
<el-col :span="14">
<img src="../../../assets/images/profile.jpg" width="100%" alt="" srcset="">
</el-col>
<el-col :span="9" offset="1">
<p>
<span>在线状态:</span><br/>
<span>在线</span>
</p>
<p>
<span>设备级别:</span><br/>
<span>A</span>
</p>
<p>
<span>安装位置:</span><br/>
<span>在线</span>
</p>
<p>
<span>品牌型号:</span><br/>
<span>在线</span>
</p>
</el-col>
</el-row>
<el-divider></el-divider>
<el-row>
<el-col :span="7">
<BarChart2 height="100px"></BarChart2>
</el-col>
<el-col :span="7">
<BarChart height="100px"></BarChart>
</el-col>
<el-col :span="10">
<el-button round type="danger" size="mini">危险</el-button>
<p>
<span>待处理预警数:</span>
<span>待开发</span>
</p>
<p>
<span>预警总数:</span>
<span>待开发</span>
</p>
</el-col>
</el-row>
<div class="body" @click="handleDetail(cardData)">
<div class="dashboard">
<!-- 上层左侧图片右侧参数 -->
<div class="top-section">
<!-- 左侧图片 -->
<div class="card">
<div class="card-header">
<h2 class="card-title">
<i class="fas fa-network-wired"></i>
{{cardData.name}}
</h2>
<span class="status-badge status-online">
<i class="fas fa-circle"></i> 在线
</span>
</div>
<div class="device-box">
<div class="device-image">
<i class="fas fa-server"></i>
</div>
<div class="device-info">
<div class="info-item">
<span class="info-label">
<i class="fas fa-layer-group"></i> 设备级别
</span>
<span class="info-value">A级</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-map-marker-alt"></i> 安装位置
</span>
<span class="info-value">一层</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-tag"></i> 品牌型号
</span>
<span class="info-value">Cisco</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-heartbeat"></i> 运行状态
</span>
<span class="info-value">运行正常</span>
</div>
</div>
</div>
<div class="metrics-grid">
<div class="metric-card">
<div class="metric-value cpu-usage">66%</div>
<div class="metric-label">CPU占用</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 66%"></div>
</div>
</div>
<div class="metric-card">
<div class="metric-value cpu-usage">66%</div>
<div class="metric-label">内存占用</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 66%"></div>
</div>
</div>
<div class="metric-card">
<div class="metric-value alert-pending">待开发</div>
<div class="metric-label">待处理预警数</div>
</div>
<div class="metric-card">
<div class="metric-value alert-total">待开发</div>
<div class="metric-label">预警总数</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import BarChart from './BarChart1.vue'
import BarChart2 from './BarChart2.vue'
export default {
name: "cardItem",
components: { BarChart, BarChart2 },
props: {
cardData: {
type: Object,
default: () => ({})
}
},
data() {
return {
}
},
created() {
mounted() {
// this.initCharts();
},
methods: {
initCharts() {
//
const performanceChart = echarts.init(document.getElementById('performanceChart'));
performanceChart.setOption({
tooltip: {
trigger: 'axis'
},
legend: {
data: ['CPU使用率', '内存使用率'],
textStyle: {
color: '#718096'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00', '24:00'],
axisLine: {
lineStyle: {
color: '#cbd5e0'
}
},
axisLabel: {
color: '#718096'
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: '#cbd5e0'
}
},
axisLabel: {
color: '#718096',
formatter: '{value}%'
},
splitLine: {
lineStyle: {
color: 'rgba(203, 213, 224, 0.6)'
}
}
},
series: [
{
name: 'CPU使用率',
type: 'line',
smooth: true,
data: [45, 52, 38, 66, 58, 62, 48],
lineStyle: {
color: '#ed8936'
},
itemStyle: {
color: '#ed8936'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'rgba(237, 137, 54, 0.3)'
}, {
offset: 1, color: 'rgba(237, 137, 54, 0.1)'
}]
}
}
},
{
name: '内存使用率',
type: 'line',
smooth: true,
data: [30, 45, 35, 50, 42, 38, 32],
lineStyle: {
color: '#4299e1'
},
itemStyle: {
color: '#4299e1'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'rgba(66, 153, 225, 0.3)'
}, {
offset: 1, color: 'rgba(66, 153, 225, 0.1)'
}]
}
}
}
]
});
//
window.addEventListener('resize', function() {
performanceChart.resize();
trafficChart.resize();
});
},
/** 查看详情 */
handleDetail: function(row) {
console.log("%c 🖍: row ", "font-size:16px;background-color:#3c235b;color:white;", row)
const userId = row.pointerId
console.log("%c 🐋: row ", "font-size:16px;background-color:#46dc4d;color:black;", row)
const userId = row.id
this.$router.push("/inMonitoring/devicesState-detail/detail/" + userId)
},
}
}
</script>
</script>
<style lang="scss" scoped>
.body {
color: #2d3748;
line-height: 1.6;
min-height: 100vh;
}
.dashboard {
max-width: 1400px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 40px;
padding: 25px;
border-radius: 20px;
}
.header h1 {
color: #2d3748;
margin-bottom: 10px;
font-size: 36px;
font-weight: 700;
background: linear-gradient(90deg, #4299e1, #38b2ac);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.header p {
color: #718096;
font-size: 18px;
}
.top-section {
display: grid;
// grid-template-columns: 1fr 2fr;
gap: 30px;
}
.bottom-section {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 30px;
}
.card {
background: rgba(255, 255, 255, 0.9);
border-radius: 20px;
padding: 10px 30px 30px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.9);
transition: all 0.4s ease;
position: relative;
overflow: hidden;
}
.card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #4299e1, #38b2ac);
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.12);
border-color: rgba(66, 153, 225, 0.3);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25px;
// padding-bottom: 15px;
border-bottom: 1px solid rgba(226, 232, 240, 0.8);
}
.card-title {
font-size: 22px;
font-weight: 700;
color: #2d3748;
display: flex;
align-items: center;
gap: 12px;
}
.card-title i {
color: #4299e1;
font-size: 24px;
}
.status-badge {
padding: 6px 15px;
border-radius: 20px;
font-size: 13px;
font-weight: 600;
}
.status-online {
background: rgba(72, 187, 120, 0.15);
color: #38a169;
border: 1px solid rgba(72, 187, 120, 0.3);
}
.status-danger {
background: rgba(245, 101, 101, 0.15);
color: #e53e3e;
border: 1px solid rgba(245, 101, 101, 0.3);
}
.device-image {
width: 100%;
height: 280px;
background: linear-gradient(135deg, #edf2f7, #e2e8f0);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
border: 1px solid rgba(226, 232, 240, 0.8);
}
.device-image i {
font-size: 80px;
color: #4299e1;
opacity: 0.8;
}
.device-box {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 15px;
}
.device-info {
display: grid;
grid-template-columns: 1fr;
gap: 15px;
}
.info-item {
display: flex;
flex-direction: column;
padding: 4px 12px;
background: rgba(255, 255, 255, 0.7);
border-radius: 12px;
border: 1px solid rgba(226, 232, 240, 0.8);
transition: all 0.3s ease;
}
.info-item: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);
}
.info-label {
font-size: 13px;
color: #718096;
margin-bottom: 6px;
display: flex;
align-items: center;
gap: 6px;
}
.info-label i {
font-size: 12px;
color: #4299e1;
}
.info-value {
font-size: 14px;
font-weight: 600;
color: #2d3748;
}
.chart-container {
width: 100%;
height: 300px;
margin-top: 10px;
}
.metrics-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-top: 20px;
}
.metric-card {
padding: 10px;
background: rgba(255, 255, 255, 0.7);
border-radius: 12px;
border: 1px solid rgba(226, 232, 240, 0.8);
text-align: center;
transition: all 0.3s ease;
}
.metric-card:hover {
background: rgba(255, 255, 255, 0.9);
border-color: rgba(66, 153, 225, 0.3);
transform: translateY(-3px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.metric-value {
font-size: 24px;
font-weight: 700;
margin-bottom: 8px;
}
.metric-label {
font-size: 14px;
color: #718096;
}
.cpu-usage {
color: #ed8936;
}
.alert-pending {
color: #e53e3e;
}
.alert-total {
color: #4299e1;
}
.progress-bar {
height: 8px;
background: rgba(226, 232, 240, 0.8);
border-radius: 4px;
overflow: hidden;
margin-top: 10px;
}
.progress-fill {
height: 100%;
border-radius: 4px;
transition: width 0.8s ease;
background: linear-gradient(90deg, #ed8936, #dd6b20);
box-shadow: 0 0 10px rgba(237, 137, 54, 0.3);
}
@media (max-width: 1024px) {
.top-section, .bottom-section {
grid-template-columns: 1fr;
}
}
</style>

@ -1,198 +1,679 @@
<template>
<div class="app-container">
<el-row :gutter="5">
<el-col :span="24">
<el-card>
<el-row>
<el-col :span="4">
<h3>交换机</h3>
</el-col>
<el-col :span="4">
<h3>持续在线XXXXX小时</h3>
</el-col>
</el-row>
<el-divider></el-divider>
<div class="body">
<div class="dashboard">
<!-- 上层左侧图片右侧参数 -->
<div class="top-section0">
<div class="card">
<div class="card-header">
<h2 class="card-title">
<i class="fas fa-network-wired"></i>
设备概览
</h2>
<span class="status-badge status-online">
<i class="fas fa-circle"></i> 在线
</span>
</div>
<div class="top-section-con">
<div class="device-image">
<i class="fas fa-server"></i>
</div>
<!-- 设备基本信息 -->
<div class="device-info">
<div class="info-title">设备基本信息</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-layer-group"></i> 设备级别
</span>
<span class="info-value">A级</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-map-marker-alt"></i> 安装位置
</span>
<span class="info-value">数据中心-主柜</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-tag"></i> 品牌型号
</span>
<span class="info-value">Cisco</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-heartbeat"></i> 运行状态
</span>
<span class="info-value">运行正常</span>
</div>
</div>
<el-row>
<el-col :span="8">
<h3>交换机</h3>
</el-col>
<el-col :span="4">
<h3>设备基本信息</h3>
<p>
<span>设备型号:</span>
<span>待开发</span>
</p>
<p>
<span>设备级别:</span>
<span>待开发</span>
</p>
<p>
<span>设备版本:</span>
<span>待开发</span>
</p>
<p>
<span>设备类型:</span>
<span>待开发</span>
</p>
</el-col>
<el-col :span="4">
<h3>设备出厂信息</h3>
<p>
<span>生产商名称:</span>
<span>待开发</span>
</p>
<p>
<span>供货商名称:</span>
<span>待开发</span>
</p>
<p>
<span>出厂日期:</span>
<span>待开发</span>
</p>
<p>
<span>质保时间:</span>
<span>待开发</span>
</p>
<p>
<span>联系人:</span>
<span>待开发</span>
</p>
<p>
<span>联系电话:</span>
<span>待开发</span>
</p>
</el-col>
<el-col :span="4">
<h3>设备管理信息</h3>
<p>
<span>带外IP管理:</span>
<span>待开发</span>
</p>
<p>
<span>安装位置:</span>
<span>待开发</span>
</p>
<p>
<span>安装日期:</span>
<span>待开发</span>
</p>
<p>
<span>服役年限:</span>
<span>待开发</span>
</p>
<p>
<span>管理员:</span>
<span>待开发</span>
</p>
</el-col>
<el-col :span="4">
<h3>设备状态信息</h3>
<p>
<span>累计预警次数:</span>
<span>待开发</span>
</p>
<p>
<span>累计维修次数:</span>
<span>待开发</span>
</p>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
<el-row class="mt10" :gutter="10">
<el-col :span="12">
<el-card :style="{height: '500px'}">
<el-row>
<el-col :span="24" class="flex alignItems gap10">
<h3>设备运行数据</h3>
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-col>
<el-col :span="14">
<el-row>
<el-col :span="12">
<LineChart></LineChart>
</el-col>
<el-col :span="12">
<LineChart></LineChart>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<LineChart></LineChart>
</el-col>
<el-col :span="12">
<LineChart></LineChart>
</el-col>
</el-row>
</el-col>
<el-col :span="10">
<el-row>
<el-col :span="12">
<BarChart height="200px" :dateRange="dateRange"></BarChart>
</el-col>
<el-col :span="12">
<BarChart height="200px" :dateRange="dateRange"></BarChart>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<BarChart2 height="200px" :dateRange="dateRange"></BarChart2>
</el-col>
<el-col :span="8">
<BarChart2 height="200px" :dateRange="dateRange"></BarChart2>
</el-col>
<el-col :span="8">
<BarChart2 height="200px" :dateRange="dateRange"></BarChart2>
</el-col>
</el-row>
</el-col>
<!-- 设备基本信息 -->
<div class="device-info">
<div class="info-title">设备基本信息</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-layer-group"></i> 设备级别
</span>
<span class="info-value">A级</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-map-marker-alt"></i> 安装位置
</span>
<span class="info-value">数据中心-主柜</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-tag"></i> 品牌型号
</span>
<span class="info-value">Cisco</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-heartbeat"></i> 运行状态
</span>
<span class="info-value">运行正常</span>
</div>
</div>
</el-row>
</el-card>
</el-col>
<el-col :span="12">
<el-card :style="{height: '500px'}">
<el-tabs v-model="selectedTab">
<el-tab-pane label="历史预警" :name="1">
历史预警
</el-tab-pane>
<el-tab-pane label="接口信息" :name="2">
接口信息
</el-tab-pane>
<el-tab-pane label="其他指标" :name="3">
其他指标
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
</el-row>
</div>
<!-- 设备基本信息 -->
<div class="device-info">
<div class="info-title">设备基本信息</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-layer-group"></i> 设备级别
</span>
<span class="info-value">A级</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-map-marker-alt"></i> 安装位置
</span>
<span class="info-value">数据中心-主柜</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-tag"></i> 品牌型号
</span>
<span class="info-value">Cisco</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-heartbeat"></i> 运行状态
</span>
<span class="info-value">运行正常</span>
</div>
</div>
<!-- 设备基本信息 -->
<div class="device-info">
<div class="info-title">设备基本信息</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-layer-group"></i> 设备级别
</span>
<span class="info-value">A级</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-map-marker-alt"></i> 安装位置
</span>
<span class="info-value">数据中心-主柜</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-tag"></i> 品牌型号
</span>
<span class="info-value">Cisco</span>
</div>
<div class="info-item">
<span class="info-label">
<i class="fas fa-heartbeat"></i> 运行状态
</span>
<span class="info-value">运行正常</span>
</div>
</div>
</div>
</div>
</div>
<!-- 下层图表加参数 -->
<div class="bottom-section">
<!-- 左侧图表 -->
<div class="card">
<div class="card-header">
<h2 class="card-title">
<i class="fas fa-chart-bar"></i>
设备运行数据
</h2>
<el-date-picker
v-model="daterange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</div>
<div class="chart-container" id="performanceChart"></div>
<div class="chart-container" id="trafficChart"></div>
</div>
<!-- 右侧参数 -->
<div class="card">
<div class="card-header">
<div class="tab-top">
<div class="top-item" v-for="(i,k) in tabs" :key="k" :class="k == tabIndex ?'ac':''" @click="tabIndex = k">
<span>{{ i.name }}</span>
</div>
</div>
</div>
<div class="metrics-grid">
<div class="bottom-item" v-if="tabIndex == 0">
<History/>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import BarChart from './BarChart1.vue'
import LineChart from './LineChart.vue'
import BarChart2 from './BarChart2.vue'
import * as echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import History from './history.vue'
export default {
name: "cardItem",
components: { BarChart, BarChart2, LineChart },
components: { History },
data() {
return {
dateRange: [],
selectedTab: 1
selectedTab: 1,
tabs: [
{ name: '历史预警' },
{ name: '接口信息' },
{ name: 'VLAN信息' },
{ name: '路由表信息' },
],
tabIndex: 0,
}
},
created() {
},
mounted() {
this.initCharts();
},
methods: {
initCharts() {
//
const performanceChart = echarts.init(document.getElementById('performanceChart'));
performanceChart.setOption({
tooltip: {
trigger: 'axis'
},
legend: {
data: ['CPU使用率', '内存使用率'],
textStyle: {
color: '#718096'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00', '24:00'],
axisLine: {
lineStyle: {
color: '#cbd5e0'
}
},
axisLabel: {
color: '#718096'
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: '#cbd5e0'
}
},
axisLabel: {
color: '#718096',
formatter: '{value}%'
},
splitLine: {
lineStyle: {
color: 'rgba(203, 213, 224, 0.6)'
}
}
},
series: [
{
name: 'CPU使用率',
type: 'line',
smooth: true,
data: [45, 52, 38, 66, 58, 62, 48],
lineStyle: {
color: '#ed8936'
},
itemStyle: {
color: '#ed8936'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'rgba(237, 137, 54, 0.3)'
}, {
offset: 1, color: 'rgba(237, 137, 54, 0.1)'
}]
}
}
},
{
name: '内存使用率',
type: 'line',
smooth: true,
data: [30, 45, 35, 50, 42, 38, 32],
lineStyle: {
color: '#4299e1'
},
itemStyle: {
color: '#4299e1'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'rgba(66, 153, 225, 0.3)'
}, {
offset: 1, color: 'rgba(66, 153, 225, 0.1)'
}]
}
}
}
]
});
//
const trafficChart = echarts.init(document.getElementById('trafficChart'));
trafficChart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['入站流量', '出站流量'],
textStyle: {
color: '#718096'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
axisLine: {
lineStyle: {
color: '#cbd5e0'
}
},
axisLabel: {
color: '#718096'
}
},
yAxis: {
type: 'value',
name: 'MB/s',
axisLine: {
lineStyle: {
color: '#cbd5e0'
}
},
axisLabel: {
color: '#718096'
},
splitLine: {
lineStyle: {
color: 'rgba(203, 213, 224, 0.6)'
}
}
},
series: [
{
name: '入站流量',
type: 'bar',
data: [320, 332, 301, 334, 390, 330, 320],
itemStyle: {
color: '#4299e1'
}
},
{
name: '出站流量',
type: 'bar',
data: [220, 182, 191, 234, 290, 330, 310],
itemStyle: {
color: '#ed8936'
}
}
]
});
//
window.addEventListener('resize', function() {
performanceChart.resize();
trafficChart.resize();
});
}
}
}
</script>
<style lang="less" scoped>
<style scoped>
.body {
background: linear-gradient(135deg, #f8fafc, #e2e8f0);
color: #2d3748;
line-height: 1.6;
padding: 20px;
min-height: 100vh;
}
.dashboard {
max-width: 1400px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 40px;
padding: 25px;
background: rgba(255, 255, 255, 0.8);
border-radius: 20px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.9);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
}
.header h1 {
color: #2d3748;
margin-bottom: 10px;
font-size: 36px;
font-weight: 700;
background: linear-gradient(90deg, #4299e1, #38b2ac);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.header p {
color: #718096;
font-size: 18px;
}
.top-section0 {
margin-bottom: 20px;
}
.top-section-con {
display: grid;
grid-template-columns: 3fr 1fr 1fr 1fr 1fr;
gap: 30px;
}
.top-section {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 30px;
margin-bottom: 30px;
}
.bottom-section {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.card {
background: rgba(255, 255, 255, 0.9);
border-radius: 20px;
padding: 30px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.9);
transition: all 0.4s ease;
position: relative;
overflow: hidden;
}
.card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #4299e1, #38b2ac);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25px;
padding-bottom: 15px;
border-bottom: 1px solid rgba(226, 232, 240, 0.8);
}
.card-title {
font-size: 18px;
font-weight: 700;
color: #2d3748;
display: flex;
align-items: center;
gap: 12px;
}
.card-title i {
color: #4299e1;
font-size: 24px;
}
.status-badge {
padding: 6px 15px;
border-radius: 20px;
font-size: 13px;
font-weight: 600;
}
.status-online {
background: rgba(72, 187, 120, 0.15);
color: #38a169;
border: 1px solid rgba(72, 187, 120, 0.3);
}
.status-danger {
background: rgba(245, 101, 101, 0.15);
color: #e53e3e;
border: 1px solid rgba(245, 101, 101, 0.3);
}
.device-image {
width: 100%;
height: 400px;
background: linear-gradient(135deg, #edf2f7, #e2e8f0);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
/* margin-bottom: 20px; */
overflow: hidden;
border: 1px solid rgba(226, 232, 240, 0.8);
}
.device-image i {
font-size: 80px;
color: #4299e1;
opacity: 0.8;
}
.device-info {
display: grid;
grid-template-columns: 1fr;
gap: 15px;
}
.info-title {
color: #2d3748;
font-size: 16px;
font-weight: 600;
text-align: center;
}
.info-item {
display: flex;
flex-direction: column;
padding: 12px;
background: rgba(255, 255, 255, 0.7);
border-radius: 12px;
border: 1px solid rgba(226, 232, 240, 0.8);
transition: all 0.3s ease;
}
.info-item: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);
}
.info-label {
font-size: 13px;
color: #718096;
margin-bottom: 6px;
display: flex;
align-items: center;
gap: 6px;
}
.info-label i {
font-size: 12px;
color: #4299e1;
}
.info-value {
font-size: 14px;
font-weight: 600;
color: #2d3748;
}
.chart-container {
width: 100%;
height: 300px;
margin-top: 10px;
}
.metrics-grid {
margin-top: 20px;
}
.metric-card {
padding: 20px;
background: rgba(255, 255, 255, 0.7);
border-radius: 12px;
border: 1px solid rgba(226, 232, 240, 0.8);
text-align: center;
transition: all 0.3s ease;
}
.metric-card:hover {
background: rgba(255, 255, 255, 0.9);
border-color: rgba(66, 153, 225, 0.3);
transform: translateY(-3px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.metric-value {
font-size: 32px;
font-weight: 700;
margin-bottom: 8px;
}
.metric-label {
font-size: 14px;
color: #718096;
}
.cpu-usage {
color: #ed8936;
}
.alert-pending {
color: #e53e3e;
}
.alert-total {
color: #4299e1;
}
.progress-bar {
height: 8px;
background: rgba(226, 232, 240, 0.8);
border-radius: 4px;
overflow: hidden;
margin-top: 10px;
}
.progress-fill {
height: 100%;
border-radius: 4px;
transition: width 0.8s ease;
background: linear-gradient(90deg, #ed8936, #dd6b20);
box-shadow: 0 0 10px rgba(237, 137, 54, 0.3);
}
@media (max-width: 1024px) {
.top-section, .bottom-section {
grid-template-columns: 1fr;
}
}
</style>
.tab-top{
display: flex;
gap: 20px;
}
.top-item{
color: #2d3748;
font-weight: 400;
font-size:18px ;
cursor: pointer;
}
.top-item.ac{
font-weight: 600;
border-bottom: 2px solid #2d3748;
}
</style>

@ -0,0 +1,69 @@
<template>
<div class="">
<el-row :gutter="20">
<el-col>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column
label="序号"
width="60"
type="index"
></el-table-column>
<el-table-column label="预警时间" align="center" key="id" prop="id"/>
<el-table-column label="预警等级" align="center" key="name" prop="name" :show-overflow-tooltip="true" />
<el-table-column label="预警信息" align="center" key="description" prop="description" :show-overflow-tooltip="true" />
<el-table-column label="预警状态" align="center" key="createBy" prop="createBy" :show-overflow-tooltip="true" />
<el-table-column label="处理人" align="center" key="createBy" prop="createBy" :show-overflow-tooltip="true" />
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
</el-col>
</el-row>
</div>
</template>
<script>
import { list, del, add, update } from "@/api/device/deviceType"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import { Splitpanes, Pane } from "splitpanes"
import "splitpanes/dist/splitpanes.css"
export default {
name: "User",
dicts: ['sys_normal_disable', 'sys_user_sex'],
components: { Treeselect, Splitpanes, Pane },
data() {
return {
//
loading: true,
//
total: 0,
//
userList: null,
//
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined
},
}
},
created() {
this.getList()
},
methods: {
/** 查询类型列表 */
getList() {
this.loading = true
list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false
}
)
}
}
}
</script>

@ -36,12 +36,10 @@
</el-form-item>
</el-form>
<div class="app-container" v-loading="loading">
<div class="bodyBox" v-loading="loading">
<el-row :gutter="10">
<el-col :span="8" class="card-box" v-for="(i,k) in userList" :key="k" @click="handleDetail(i)">
<el-card>
<cardItem/>
</el-card>
<el-col :span="8" class="card-box" v-for="(i,k) in userList" :key="k" >
<cardItem class="cursor" :cardData="i"/>
</el-col>
</el-row>
</div>
@ -148,7 +146,7 @@
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/inMonitoring/devicesState"
import { list, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus } from "@/api/inMonitoring/devicesState"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import cardItem from "./cardItem.vue"
@ -274,16 +272,12 @@ export default {
},
created() {
this.getList()
// this.getDeptTree()
this.getConfigKey("sys.user.initPassword").then(response => {
this.initPassword = response.msg
})
},
methods: {
/** 查询设备列表 */
getList() {
this.loading = true
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false
@ -383,11 +377,6 @@ export default {
this.form.password = this.initPassword
})
},
/** 查看详情 */
handleDetail: function(row) {
const userId = row.userId
this.$router.push("/inMonitoring/devicesState-detail/detail/" + userId)
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
@ -486,4 +475,17 @@ export default {
}
}
}
</script>
</script>
<style scoped>
.bodyBox{
background: linear-gradient(135deg, #f8fafc, #e2e8f0);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.9);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
padding: 10px;
}
.cursor{
cursor: pointer;
}
</style>

@ -1,509 +0,0 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<splitpanes :horizontal="this.$store.getters.device === 'mobile'" class="default-theme">
<!--类型类型管理-->
<pane size="84">
<el-col>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="类型名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入类型名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="类型状态" clearable style="width: 240px">
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['device:deviceType:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['device:deviceType:import']">导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['device:deviceType:export']">导出</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
<el-table-column label="名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="描述" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="触发条件" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="预警等级" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="预警方式" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="预警消息" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope" v-if="scope.row.userId !== 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-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:deviceType:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
</el-col>
</pane>
</splitpanes>
</el-row>
<el-dialog :title="title" :visible.sync="open" width="760px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="90px">
<el-row :gutter="20">
<!-- 类型昵称 + 手机号码 -->
<el-col :span="12">
<el-form-item label="类型昵称" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入类型昵称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
</el-col>
<!-- 邮箱 + 类型名称 -->
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="类型名称" prop="userName">
<el-input v-model="form.userName" placeholder="请输入类型名称" maxlength="30" />
</el-form-item>
</el-col>
<!-- 类型密码仅新增+ 类型性别 -->
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="类型密码" prop="password">
<el-input v-model="form.password" placeholder="请输入类型密码" type="password" maxlength="20" show-password />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="类型性别">
<el-select v-model="form.sex" placeholder="请选择性别" style="width: 100%">
<el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<!-- 状态 + 角色 -->
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="角色">
<el-select v-model="form.roleIds" multiple placeholder="请选择角色" style="width: 100%">
<el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option>
</el-select>
</el-form-item>
</el-col>
<!-- 备注单独一行 -->
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入内容" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</span>
</el-dialog>
<!-- 类型导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<div class="el-upload__tip" slot="tip">
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的类型数据
</div>
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/inMonitoring/earlyWarning"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import { Splitpanes, Pane } from "splitpanes"
import "splitpanes/dist/splitpanes.css"
export default {
name: "User",
dicts: ['sys_normal_disable', 'sys_user_sex'],
components: { Treeselect, Splitpanes, Pane },
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
userList: null,
//
title: "",
//
deptOptions: undefined,
//
enabledDeptOptions: undefined,
//
open: false,
//
deptName: undefined,
//
initPassword: undefined,
//
dateRange: [],
//
postOptions: [],
//
roleOptions: [],
//
form: {},
defaultProps: {
children: "children",
label: "label"
},
//
upload: {
//
open: false,
//
title: "",
//
isUploading: false,
//
updateSupport: 0,
//
headers: { Authorization: "Bearer " + getToken() },
//
url: process.env.VUE_APP_BASE_API + "/system/user/importData"
},
//
queryParams: {
pageNum: 1,
pageSize: 10,
userName: undefined,
phonenumber: undefined,
status: undefined,
deptId: undefined
},
//
columns: [
{ key: 0, label: '类型编号', visible: true, showInSelector: true },
{ key: 1, label: '类型名称', visible: true, showInSelector: true },
{ key: 2, label: '类型昵称', visible: true, showInSelector: true },
{ key: 3, label: '部门', visible: false, showInSelector: false }, // 👈
{ key: 4, label: '手机号码', visible: true, showInSelector: true },
{ key: 5, label: '状态', visible: true, showInSelector: true },
{ key: 6, label: '创建时间', visible: true, showInSelector: true }
],
//
rules: {
userName: [
{ required: true, message: "类型名称不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '类型名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
nickName: [
{ required: true, message: "类型昵称不能为空", trigger: "blur" }
],
password: [
{ required: true, message: "类型密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '类型密码长度必须介于 5 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
],
email: [
{
type: "email",
message: "请输入正确的邮箱地址",
trigger: ["blur", "change"]
}
],
phonenumber: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur"
}
]
}
}
},
watch: {
//
deptName(val) {
this.$refs.tree.filter(val)
}
},
created() {
this.getList()
// this.getDeptTree()
this.getConfigKey("sys.user.initPassword").then(response => {
this.initPassword = response.msg
})
},
methods: {
/** 查询类型列表 */
getList() {
this.loading = true
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false
}
)
},
// /** */
// getDeptTree() {
// deptTreeSelect().then(response => {
// this.deptOptions = response.data
// this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
// })
// },
//
filterDisabledDept(deptList) {
return deptList.filter(dept => {
if (dept.disabled) {
return false
}
if (dept.children && dept.children.length) {
dept.children = this.filterDisabledDept(dept.children)
}
return true
})
},
//
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
//
handleNodeClick(data) {
this.queryParams.deptId = data.id
this.handleQuery()
},
//
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
this.$modal.confirm('确认要"' + text + '""' + row.userName + '"类型吗?').then(function() {
return changeUserStatus(row.userId, row.status)
}).then(() => {
this.$modal.msgSuccess(text + "成功")
}).catch(function() {
row.status = row.status === "0" ? "1" : "0"
})
},
//
cancel() {
this.open = false
this.reset()
},
//
reset() {
this.form = {
userId: undefined,
deptId: undefined,
userName: undefined,
nickName: undefined,
password: undefined,
phonenumber: undefined,
email: undefined,
sex: undefined,
status: "0",
remark: undefined,
postIds: [],
roleIds: []
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = []
this.resetForm("queryForm")
this.queryParams.deptId = undefined
this.$refs.tree.setCurrentKey(null)
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.userId)
this.single = selection.length != 1
this.multiple = !selection.length
},
//
handleCommand(command, row) {
switch (command) {
case "handleResetPwd":
this.handleResetPwd(row)
break
case "handleAuthRole":
this.handleAuthRole(row)
break
default:
break
}
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
getUser().then(response => {
this.postOptions = response.posts
this.roleOptions = response.roles
this.open = true
this.title = "添加类型"
this.form.password = this.initPassword
})
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const userId = row.userId || this.ids
getUser(userId).then(response => {
this.form = response.data
this.postOptions = response.posts
this.roleOptions = response.roles
this.$set(this.form, "postIds", response.postIds)
this.$set(this.form, "roleIds", response.roleIds)
this.open = true
this.title = "修改类型"
this.form.password = ""
})
},
/** 重置密码按钮操作 */
handleResetPwd(row) {
this.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "类型密码长度必须介于 5 和 20 之间",
inputValidator: (value) => {
if (/<|>|"|'|\||\\/.test(value)) {
return "不能包含非法字符:< > \" ' \\\ |"
}
},
}).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => {})
},
/** 分配角色操作 */
handleAuthRole: function(row) {
const userId = row.userId
this.$router.push("/system/user-auth/role/" + userId)
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.userId != undefined) {
updateUser(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addUser(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const userIds = row.userId || this.ids
this.$modal.confirm('是否确认删除类型编号为"' + userIds + '"的数据项?').then(function() {
return delUser(userIds)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('system/user/export', {
...this.queryParams
}, `user_${new Date().getTime()}.xlsx`)
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = "类型导入"
this.upload.open = true
},
/** 下载模板操作 */
importTemplate() {
this.download('system/user/importTemplate', {
}, `user_template_${new Date().getTime()}.xlsx`)
},
//
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true
},
//
handleFileSuccess(response, file, fileList) {
this.upload.open = false
this.upload.isUploading = false
this.$refs.upload.clearFiles()
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
this.getList()
},
//
submitFileForm() {
this.$refs.upload.submit()
}
}
}
</script>

@ -0,0 +1,321 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<splitpanes :horizontal="this.$store.getters.device === 'mobile'" class="default-theme">
<!--设备档案-->
<pane size="84">
<el-col>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<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-form-item>
<el-form-item label="预警等级" prop="level">
<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-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="处理状态" clearable style="width: 240px">
<el-option v-for="dict in dict.type.alert_message_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- <el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['device:files:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['device:files:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['device:files:import']">导入</el-button>
</el-col>
</el-row> -->
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column
label="序号"
width="60"
type="index"
></el-table-column>
<el-table-column label="预警时间" align="center" key="occurTime" prop="occurTime" />
<el-table-column label="预警等级" align="center" key="level" prop="level" :show-overflow-tooltip="true" />
<el-table-column label="预警信息" align="center" key="version" prop="version" :show-overflow-tooltip="true" />
<el-table-column label="预警状态" align="center" key="status">
<template slot-scope="scope">
<dict-tag :options="dict.type.alert_message_status" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="处理人" align="center" key="handler" prop="handler" width="120" />
<el-table-column label="处理时间" align="center" prop="handleTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.handleTime) }}</span>
</template>
</el-table-column>
<el-table-column label="解决方案" align="center" key="solution" prop="solution" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" v-if="scope.row.status == 'UNHANDLED'" type="text" @click="handleUpdate(scope.row)" v-hasPermi="['device:files:edit']">去处理</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
</el-col>
</pane>
</splitpanes>
</el-row>
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body :close-on-click-modal="false">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="解决人" prop="handler">
<el-input v-model="form.handler" placeholder="请输入解决人" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="解决方法" prop="solution">
<el-input v-model="form.solution" placeholder="请输入解决方法" type="textarea" :rows="3" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { getDict, list, getInfo, del, add, update } from "@/api/inMonitoring/message"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import { Splitpanes, Pane } from "splitpanes"
import "splitpanes/dist/splitpanes.css"
export default {
name: "User",
dicts: ['device_disable', 'sys_user_sex', 'warning_level','alert_message_status'],
components: { Treeselect, Splitpanes, Pane },
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
dataList: null,
//
title: "",
//
deptOptions: undefined,
//
enabledDeptOptions: undefined,
//
open: false,
//
deptName: undefined,
//
initPassword: undefined,
//
dateRange: [],
//
postOptions: [],
//
roleOptions: [],
//
form: {},
defaultProps: {
children: "children",
label: "label"
},
//
upload: {
//
open: false,
//
title: "",
//
isUploading: false,
//
updateSupport: 0,
//
headers: { Authorization: "Bearer " + getToken() },
//
url: process.env.VUE_APP_BASE_API + "/equipment/import"
},
//
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined,
status: undefined
},
//
rules: {
handler: [
{ required: true, message: "解决人不能为空", trigger: "blur" },
],
solution: [
{ required: true, message: "解决方法不能为空", trigger: "blur" }
]
}
}
},
watch: {
//
deptName(val) {
this.$refs.tree.filter(val)
}
},
created() {
this.getList()
},
methods: {
/** 查询设备列表 */
getList() {
this.loading = true
list({minTime:this.dateRange[0],maxTime:this.dateRange[1],...this.queryParams}).then(response => {
this.dataList = response.rows
this.total = response.total
this.loading = false
}
)
},
upImage(fileList){
console.log(fileList)
this.form.image = fileList
},
//
cancel() {
this.open = false
this.reset()
},
//
reset() {
this.form = {
id: undefined,
deptId: undefined,
name: undefined,
nickName: undefined,
password: undefined,
phonenumber: undefined,
email: undefined,
sex: undefined,
status: "0",
remark: undefined,
postIds: [],
roleIds: []
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = []
this.resetForm("queryForm")
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length != 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = "添加设备"
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
this.form = {...row}
this.open = true
this.title = "处理"
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != undefined) {
update(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
add(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const Ids = row.id || this.ids
this.$modal.confirm('是否确认删除设备ID为"' + Ids + '"的数据项?').then(function() {
return del(Ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = "设备导入"
this.upload.open = true
},
/** 下载模板操作 */
importTemplate() {
this.download('system/user/importTemplate', {
}, `user_template_${new Date().getTime()}.xlsx`)
},
//
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true
},
//
handleFileSuccess(response, file, fileList) {
this.upload.open = false
this.upload.isUploading = false
this.$refs.upload.clearFiles()
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
this.getList()
},
//
submitFileForm() {
this.$refs.upload.submit()
}
}
}
</script>

@ -0,0 +1,445 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<splitpanes :horizontal="this.$store.getters.device === 'mobile'" class="default-theme">
<!--设备档案-->
<pane size="84">
<el-col>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="预警级别">
<el-select v-model="queryParams.severity" placeholder="请选择级别" style="width: 100%">
<el-option v-for="dict in dict.type.warning_level" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['device:files:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['device:files:remove']">删除</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column
label="序号"
width="60"
type="index"
></el-table-column>
<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="center" key="alertTemplate" prop="alertTemplate" width="240" :show-overflow-tooltip="true" />
<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="alertStation" prop="alertStation" width="200" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['device:files:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:files:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
</el-col>
</pane>
</splitpanes>
</el-row>
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body :close-on-click-modal="false">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="规则名称" prop="ruleName">
<el-input v-model="form.ruleName" placeholder="请输入设备名称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="描述" prop="description">
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入内容" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="触发条件" prop="compareValue1">
<el-col :span="6">
<el-select v-model="form.paramName" placeholder="请选择" style="width: 100%">
<el-option v-for="dict in byTableData" :key="dict.columnName" :label="dict.paramName" :value="dict.columnName"></el-option>
</el-select>
</el-col>
<el-col :span="6">
<el-select v-model="form.operator" placeholder="请选择" style="width: 100%">
<el-option v-for="dict in dict.type.waming_rules" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-col>
<el-col :span="5">
<el-form-item label="" prop="compareValue1" label-width="0">
<el-input v-model="form.compareValue1" placeholder="请输入" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="1" v-if="form.operator == 'between'">
<span>~</span>
</el-col>
<el-col :span="5" v-if="form.operator == 'between'">
<el-form-item label="" prop="compareValue2" label-width="0">
<el-input v-model="form.compareValue2" placeholder="请输入" maxlength="30" />
</el-form-item>
</el-col>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预警级别" prop="severity">
<el-select v-model="form.severity" placeholder="请选择级别" style="width: 100%">
<el-option v-for="dict in dict.type.warning_level" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<!-- <el-col :span="24">
<el-form-item label="预警消息" prop="message">
<el-input v-model="form.message" type="textarea" :rows="3" placeholder="请输入内容" />
</el-form-item>
</el-col> -->
<el-col :span="24">
<el-form-item label="是否邮箱" prop="alertWay">
<el-select v-model="form.alertWay" placeholder="启用状态" clearable>
<el-option v-for="dict in alertWayOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24" v-if="form.alertWay == 'email'">
<el-form-item label="邮箱" prop="alertStation">
<el-input v-model="form.alertStation" placeholder="请输入邮箱" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</span>
</el-dialog>
<!-- 设备导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<div class="el-upload__tip" slot="tip">
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的设备档案
</div>
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { list, del, add, update, byTable } from "@/api/inMonitoring/rules"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import { Splitpanes, Pane } from "splitpanes"
import "splitpanes/dist/splitpanes.css"
export default {
name: "User",
dicts: ['warning_level', 'device_disable', 'waming_rules'],
components: { Treeselect, Splitpanes, Pane },
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
dataList: null,
//
title: "",
//
deptOptions: undefined,
//
enabledDeptOptions: undefined,
//
open: false,
//
deptName: undefined,
//
initPassword: undefined,
//
dateRange: [],
//
postOptions: [],
//
roleOptions: [],
//
form: {
id: undefined,
ruleName: undefined,
description: undefined,
paramName: undefined,
operator: undefined,
compareValue1: undefined,
compareValue2: undefined,
severity: undefined,
message: undefined,
alertWay: 'noemail',
alertStation: '',
status: "0"
},
//
byTableData: [],
alertWayOptions: [
{
value: 'noemail',
label: "否"
},
{
value: 'email',
label: "是"
}
],
defaultProps: {
children: "children",
label: "label"
},
//
upload: {
//
open: false,
//
title: "",
//
isUploading: false,
//
updateSupport: 0,
//
headers: { Authorization: "Bearer " + getToken() },
//
url: process.env.VUE_APP_BASE_API + "/equipment/import"
},
//
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined,
status: undefined
},
//
rules: {
ruleName: [
{ required: true, message: "规则名称不能为空", trigger: "blur" }
],
description: [
{ required: true, message: "规则描述不能为空", trigger: "blur" },
],
alertWay: [
{ required: true, message: "设备类型不能为空", trigger: "blur" }
],
severity: [
{ required: true, message: "设备级别不能为空", trigger: "blur" },
],
message: [
{ required: true, message: "预警消息不能为空", trigger: "blur" }
],
status: [
{ required: true, message: "状态不能为空", trigger: "blur" },
],
paramName: [
{ required: true, message: "请选择", trigger: "blur" },
],
operator: [
{ required: true, message: "请选择", trigger: "blur" },
],
compareValue1: [
{ required: true, message: "请输入", trigger: "blur" },
],
compareValue2: [
{ required: true, message: "请输入", trigger: "blur" },
],
alertStation: [
{ required: true, message: "请输入", trigger: "blur" },
{
pattern: /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/,
message: "请输入正确的邮箱",
trigger: "blur"
}
]
}
}
},
watch: {
//
deptName(val) {
this.$refs.tree.filter(val)
}
},
created() {
this.getList()
this.getByTable()
},
methods: {
/** 查询设备列表 */
getList() {
this.loading = true
list({minTime:this.dateRange[0],maxTime:this.dateRange[1],...this.queryParams}).then(response => {
this.dataList = response.rows
this.total = response.total
this.loading = false
}
)
},
getByTable() {
this.loading = true
byTable().then(response => {
console.log("%c 🇻🇳: getList -> response ", "font-size:16px;background-color:#c9f364;color:black;", response)
this.byTableData = response.data
this.loading = false
}
)
},
upImage(fileList){
console.log(fileList)
this.form.image = fileList
},
//
cancel() {
this.open = false
this.reset()
},
//
reset() {
this.form = {
email: undefined,
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = []
this.resetForm("queryForm")
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length != 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = "添加设备"
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
this.form = {...row}
this.open = true
this.title = "修改"
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
let form = {...this.form}
this.form.alertRule = {
ruleName: form.ruleName,
description: form.description,
alertStation: form.alertStation ? form.alertStation : "",
alertWay: form.alertWay,
severity: form.severity,
enable:0
}
this.form.alertRuleConditionList = [{
paramName: form.paramName,
compareValue: form.compareValue2?form.compareValue1+','+form.compareValue2:form.compareValue1,
operator: form.operator
}]
if (this.form.id != undefined) {
update(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
add(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const Ids = row.id || this.ids
this.$modal.confirm('是否确认删除设备ID为"' + Ids + '"的数据项?').then(function() {
return del(Ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = "设备导入"
this.upload.open = true
},
/** 下载模板操作 */
importTemplate() {
this.download('system/user/importTemplate', {
}, `user_template_${new Date().getTime()}.xlsx`)
},
//
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true
},
//
handleFileSuccess(response, file, fileList) {
this.upload.open = false
this.upload.isUploading = false
this.$refs.upload.clearFiles()
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
this.getList()
},
//
submitFileForm() {
this.$refs.upload.submit()
}
}
}
</script>

@ -0,0 +1,308 @@
<template>
<div class="dashboard-editor-container">
<el-row :gutter="32">
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<div class="card-title"><i class="el-icon-data-line"></i>预警信息统计</div>
<div class="data-overview">
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
</div>
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<div class="card-title"><i class="el-icon-pie-chart"></i>检测设备信息</div>
<pie-chart />
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper overflow-auto">
<div class="card-title"><i class="el-icon-monitor"></i>设备预警信息</div>
<div class="div0">
<div class="div1" v-for="(alert, index) in alerts" :key="index" :class="`alert-level-${alert.level}`">
<dv-border-box-13 class="div2">
<el-row>
<el-col span="12">
<span class="alert-lable">预警时间:{{ alert.time }}</span>
</el-col>
<el-col span="12">
<span class="alert-lable">设备名称:{{ alert.deviceName }}</span>
</el-col>
<el-col span="12">
<span class="alert-lable">设备位置:{{ alert.deviceLocation }}</span>
</el-col>
<el-col span="12">
<span class="alert-lable">预警等级:<span class="alert-lable" :style="{ color: getLevelColor(alert.level) }">{{ alert.level }}</span></span>
</el-col>
<el-col span="12">
<span class="alert-lable">预警信息:{{ alert.message }}</span>
</el-col>
<el-col span="12">
<span class="alert-lable">预警状态:{{ alert.status }}</span>
</el-col>
</el-row>
</dv-border-box-13>
</div>
</div>
</div>
</el-col>
</el-row>
<el-row style="background:#fff;padding:16px;">
<div class="card-title"><i class="el-icon-s-data"></i> 设备状态监控</div>
<dv-scroll-board :config="scrollConfig" style="height:220px;" />
</el-row>
</div>
</template>
<script>
import PanelGroup from './dashboard/PanelGroup'
import LineChart from './dashboard/LineChart'
import RaddarChart from './dashboard/RaddarChart'
import PieChart from './dashboard/PieChart'
import BarChart from './dashboard/BarChart'
import digital from './dashboard/digital'
const lineChartData = {
newVisitis: {
expectedData: [100, 120, 161, 134, 105, 160, 165],
actualData: [120, 82, 91, 154, 162, 140, 145]
},
messages: {
expectedData: [200, 192, 120, 144, 160, 130, 140],
actualData: [180, 160, 151, 106, 145, 150, 130]
},
purchases: {
expectedData: [80, 100, 121, 104, 105, 90, 100],
actualData: [120, 90, 100, 138, 142, 130, 130]
},
shoppings: {
expectedData: [130, 140, 141, 142, 145, 150, 160],
actualData: [120, 82, 91, 154, 162, 140, 130]
}
}
export default {
name: 'Index',
components: {
PanelGroup,
LineChart,
RaddarChart,
PieChart,
BarChart,
digital
},
data() {
return {
lineChartData: lineChartData.newVisitis,
scrollConfig:{
header: ['设备名称', '设备位置', 'CPU使用率','内存使用率','温度', '健康度', '设备运行时长','采集时间'],
data: [
['行1列1', '行1列2', '行1列3', '行1列4', '行1列5', '行1列6','行1列7', '行1列8'],
['行2列1', '行2列2', '行2列3', '行2列4', '行2列5', '行2列6','行2列7', '行2列8'],
['行3列1', '行3列2', '行3列3', '行3列4', '行3列5', '行3列6','行3列7', '行3列8'],
['行4列1', '行4列2', '行4列3', '行4列4', '行4列5', '行4列6','行4列7', '行4列8'],
['行5列1', '行5列2', '行5列3', '行5列4', '行5列5', '行5列6','行5列7', '行5列8'],
['行6列1', '行6列2', '行6列3', '行6列4', '行6列5', '行6列6','行6列7', '行6列8'],
['行7列1', '行7列2', '行7列3', '行7列4', '行7列5', '行7列6','行7列7', '行7列8'],
['行8列1', '行8列2', '行8列3', '行8列4', '行8列5', '行8列6','行8列7', '行8列8'],
['行9列1', '行9列2', '行9列3', '行9列4', '行9列5', '行9列6','行9列7', '行9列8'],
['行10列1', '行10列2', '行10列3', '行10列4', '行10列5', '行10列6','行10列7', '行10列8']
],
headerBGC:'#f8f8f9',
headerHeight:60,
oddRowBGC:'#f5f7fa',
evenRowBGC:'#fff',
},
alerts: [
{
time: '2021-10-16 14:54:11',
deviceName: 'PLC远程监控系统',
deviceLocation: '污水处理监控系统',
level: 1,
message: '2#电机运行状态等于1',
status: '触发值: 1'
},
{
time: '2021-10-16 14:54:04',
deviceName: 'PLC远程监控系统',
deviceLocation: '污水处理监控系统',
level: 0,
message: '2#电机运行状态报警恢复',
status: '触发值: 0'
},
{
time: '2021-10-16 14:54:11',
deviceName: 'PLC远程监控系统',
deviceLocation: '污水处理监控系统',
level: 1,
message: '2#电机运行状态等于1',
status: '触发值: 1'
},
{
time: '2021-10-16 14:54:04',
deviceName: 'PLC远程监控系统',
deviceLocation: '污水处理监控系统',
level: 0,
message: '2#电机运行状态报警恢复',
status: '触发值: 0'
},
//
]
}
},
methods: {
handleSetLineChartData(type) {
this.lineChartData = lineChartData[type]
},
getLevelColor(level) {
const levelColors = {
0: 'green',
1: 'orange',
2: 'red'
};
return levelColors[level] || 'black'; //
}
}
}
</script>
<style lang="scss" scoped>
.dashboard-editor-container {
padding: 32px;
background-color: rgb(240, 242, 245);
position: relative;
.chart-wrapper {
background: #fff;
padding: 16px;
margin-bottom: 32px;
height: 420px;
}
}
@media (max-width:1024px) {
.chart-wrapper {
padding: 8px;
}
}
.dv-scroll-board{
color: #3d3d3d;
}
.card-title {
font-size: 16px;
margin-bottom: 15px;
display: flex;
align-items: center;
color: #3d3d3d;
font-weight: bold;
}
.card-title i {
margin-right: 8px;
font-size: 18px;
}
.data-overview {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.data-item {
flex: 1;
min-width: 30%;
text-align: center;
padding: 15px 10px;
background: #f5f7fa;
border-radius: 8px;
transition: all 0.3s ease;
}
.data-item:hover {
background: #f1f2f4;
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
.data-value {
font-size: 24px;
font-weight: bold;
margin: 10px 0;
color: #3d3d3d;
}
.data-label {
font-size: 14px;
color: #3d3d3d;
}
.alert-list .div0 {
list-style-type: none;
padding: 0;
}
.overflow-auto {
overflow: auto;
}
.alert-list {
background-color: #fff;
padding: 16px;
margin-bottom: 32px;
}
.alert-list .div1 {
display: flex;
justify-content: space-between;
}
.div1{
margin-bottom: 5px;
}
.div2{
padding: 20px 16px;
}
.alert-time, .alert-device-name, .alert-device-location, .alert-message, .alert-status {
flex: 1;
}
.alert-level {
flex: 0.5;
text-align: center;
}
</style>

@ -1,94 +1,132 @@
<template>
<div class="dashboard-editor-container">
<el-row :gutter="32">
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<div class="card-title"><i class="el-icon-data-line"></i>预警信息统计</div>
<div class="data-overview">
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
<div class="body">
<div class="container">
<!-- 上层三个模块并排 -->
<div class="top-section">
<!-- 预警信息统计 -->
<div class="panel">
<div class="card">
<div class="card-header">
<h2 class="card-title"><i class="fas fa-exclamation-triangle"></i> 预警信息统计</h2>
</div>
<div class="stats-container">
<div class="stat-card" :class="alertMessageData.yearCount == 0?'normal':''">
<div class="stat-label">年预警总数</div>
<div class="stat-value">{{ alertMessageData.yearCount }}</div>
</div>
<div class="stat-card" :class="alertMessageData.monthCount == 0?'normal':''">
<div class="stat-label">月预警总数</div>
<div class="stat-value">{{ alertMessageData.monthCount }}</div>
</div>
<!-- 等级预警 -->
<div class="stat-card" :class="i.count == 0?'normal':i.count>10?'warning':''" v-for="(i,k) in alertMessageData.levelCount" :key="k">
<div class="stat-label">{{ `等级${i.level}预警` }}</div>
<div class="stat-value">{{ i.count }}</div>
</div>
<!-- 设备预警 -->
<div class="stat-card" :class="i.count == 0?'normal':i.count>10?'warning':''" v-for="(i,k) in alertMessageData.typeCount" :key="k">
<div class="stat-label">{{ `${i.name}预警` }}</div>
<div class="stat-value">{{ i.count }}</div>
</div>
</div>
</div>
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
<!-- 检测设备信息 -->
<div class="panel">
<div class="card">
<div class="card-header">
<h2 class="card-title"><i class="fas fa-microchip"></i> 检测设备信息</h2>
</div>
<ul class="device-list">
<li class="device-item" v-for="device in devices" :key="device.id" :class="device.status">
<div class="device-icon">
<i :class="device.icon"></i>
</div>
<div class="device-info">
<div class="device-name">{{ device.name }}</div>
<div class="device-details">{{ device.description }}</div>
</div>
<span :class="device.status === 'UNHANDLED' ? 'alert-badge' : 'normal-badge'">
{{ device.status === 'UNHANDLED' ? '预警中' : '正常' }}
</span>
</li>
</ul>
</div>
</div>
<div class="data-item">
<div class="data-label">预警总数</div>
<digital :configData="{number:[111]}" />
<!-- 设备预警信息 -->
<div class="panel">
<div class="card">
<div class="card-header">
<h2 class="card-title"><i class="fas fa-bell"></i> 设备预警信息</h2>
</div>
<ul class="device-list" v-infinite-scroll="loadMore" :infinite-scroll-disabled="isLoading || noMore" infinite-scroll-distance="50" infinite-scroll-delay="300">
<li class="device-item" v-for="alert in alerts" :key="alert.id" :class="alert.status === 'UNHANDLED' ? 'warning' : 'normal'" >
<div class="device-icon">
<i :class="alert.status === 'UNHANDLED' ? 'fas fa-exclamation-circle' : 'fas fa-check-circle'"></i>
</div>
<div class="device-info">
<div class="device-name">{{ alert.name }}</div>
<div class="device-details">
<div>预警时间: {{ parseTime(alert.occurTime) }}</div>
<div>设备位置: {{ alert.location }}</div>
<div>预警信息: {{ alert.message }}</div>
</div>
</div>
<span :class="alert.status === 'UNHANDLED' ? 'alert-badge' : 'normal-badge'">
{{ '等级'+alert.level }}
</span>
</li>
<p v-if="isLoading">加载中...</p>
<p v-if="noMore">没有更多了</p>
</ul>
</div>
</div>
</div>
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<div class="card-title"><i class="el-icon-pie-chart"></i>检测设备信息</div>
<pie-chart />
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<div class="card-title"><i class="el-icon-monitor"></i>设备预警信息</div>
<div class="div0">
<div class="div1" v-for="(alert, index) in alerts" :key="index" :class="`alert-level-${alert.level}`">
<dv-border-box-13 class="div2">
<el-row>
<el-col span="12">
<span class="alert-lable">预警时间:{{ alert.time }}</span>
</el-col>
<el-col span="12">
<span class="alert-lable">设备名称:{{ alert.deviceName }}</span>
</el-col>
<el-col span="12">
<span class="alert-lable">设备位置:{{ alert.deviceLocation }}</span>
</el-col>
<el-col span="12">
<span class="alert-lable">预警等级:<span class="alert-lable" :style="{ color: getLevelColor(alert.level) }">{{ alert.level }}</span></span>
</el-col>
<el-col span="12">
<span class="alert-lable">预警信息:{{ alert.message }}</span>
</el-col>
<el-col span="12">
<span class="alert-lable">预警状态:{{ alert.status }}</span>
</el-col>
</el-row>
</dv-border-box-13>
<!-- 下层设备状态监控独立一行 -->
<div class="bottom-section">
<div class="card full-width">
<div class="card-header">
<h2 class="card-title"><i class="fas fa-desktop"></i> 设备状态监控</h2>
<div class="last-update">最后更新: {{ lastUpdate }}</div>
</div>
<div class="table-container">
<table>
<thead>
<tr>
<th v-for="header in tableHeaders" :key="header">{{ header }}</th>
</tr>
</thead>
<tbody>
<tr v-for="device in deviceStatus" :key="device.id">
<td>{{ device.name }}</td>
<td>{{ device.location }}</td>
<td>
<span :class="getCpuStatus(device.cpuUsage)"></span>
{{ device.cpuUsage }}%
</td>
<td>
<span :class="getMemoryStatus(device.memoryUsage)"></span>
{{ device.memoryUsage }}%
</td>
<td>{{ device.temperature }}°C</td>
<td>
<div class="health-bar">
<div class="health-fill" :class="getHealthStatus(device.health)"></div>
</div>
{{ device.health }}%
</td>
<td>{{ device.uptime }}</td>
<td>{{ device.collectionTime }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</el-col>
</el-row>
<el-row style="background:#fff;padding:16px;">
<div class="card-title"><i class="el-icon-s-data"></i> 设备状态监控</div>
<dv-scroll-board :config="scrollConfig" style="height:220px;" />
</el-row>
</div>
</div>
</template>
@ -99,25 +137,12 @@ import RaddarChart from './dashboard/RaddarChart'
import PieChart from './dashboard/PieChart'
import BarChart from './dashboard/BarChart'
import digital from './dashboard/digital'
const lineChartData = {
newVisitis: {
expectedData: [100, 120, 161, 134, 105, 160, 165],
actualData: [120, 82, 91, 154, 162, 140, 145]
},
messages: {
expectedData: [200, 192, 120, 144, 160, 130, 140],
actualData: [180, 160, 151, 106, 145, 150, 130]
},
purchases: {
expectedData: [80, 100, 121, 104, 105, 90, 100],
actualData: [120, 90, 100, 138, 142, 130, 130]
},
shoppings: {
expectedData: [130, 140, 141, 142, 145, 150, 160],
actualData: [120, 82, 91, 154, 162, 140, 130]
}
}
import { statistic, byEquType, listMonitor, alertMessageTimes } from "@/api/index/index"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import { Splitpanes, Pane } from "splitpanes"
import "splitpanes/dist/splitpanes.css"
export default {
name: 'Index',
@ -131,170 +156,445 @@ export default {
},
data() {
return {
lineChartData: lineChartData.newVisitis,
scrollConfig:{
header: ['设备名称', '设备位置', 'CPU使用率','内存使用率','温度', '健康度', '设备运行时长','采集时间'],
data: [
['行1列1', '行1列2', '行1列3', '行1列4', '行1列5', '行1列6','行1列7', '行1列8'],
['行2列1', '行2列2', '行2列3', '行2列4', '行2列5', '行2列6','行2列7', '行2列8'],
['行3列1', '行3列2', '行3列3', '行3列4', '行3列5', '行3列6','行3列7', '行3列8'],
['行4列1', '行4列2', '行4列3', '行4列4', '行4列5', '行4列6','行4列7', '行4列8'],
['行5列1', '行5列2', '行5列3', '行5列4', '行5列5', '行5列6','行5列7', '行5列8'],
['行6列1', '行6列2', '行6列3', '行6列4', '行6列5', '行6列6','行6列7', '行6列8'],
['行7列1', '行7列2', '行7列3', '行7列4', '行7列5', '行7列6','行7列7', '行7列8'],
['行8列1', '行8列2', '行8列3', '行8列4', '行8列5', '行8列6','行8列7', '行8列8'],
['行9列1', '行9列2', '行9列3', '行9列4', '行9列5', '行9列6','行9列7', '行9列8'],
['行10列1', '行10列2', '行10列3', '行10列4', '行10列5', '行10列6','行10列7', '行10列8']
],
headerBGC:'#f8f8f9',
headerHeight:60,
oddRowBGC:'#f5f7fa',
evenRowBGC:'#fff',
},
alerts: [
{
time: '2021-10-16 14:54:11',
deviceName: 'PLC远程监控系统',
deviceLocation: '污水处理监控系统',
level: 1,
message: '2#电机运行状态等于1',
status: '触发值: 1'
},
{
time: '2021-10-16 14:54:04',
deviceName: 'PLC远程监控系统',
deviceLocation: '污水处理监控系统',
level: 0,
message: '2#电机运行状态报警恢复',
status: '触发值: 0'
},
{
time: '2021-10-16 14:54:11',
deviceName: 'PLC远程监控系统',
deviceLocation: '污水处理监控系统',
level: 1,
message: '2#电机运行状态等于1',
status: '触发值: 1'
},
{
time: '2021-10-16 14:54:04',
deviceName: 'PLC远程监控系统',
deviceLocation: '污水处理监控系统',
level: 0,
message: '2#电机运行状态报警恢复',
status: '触发值: 0'
},
//
totalAlerts: 111,
activeAlerts: 42,
resolvedAlerts: 69,
lastUpdate: new Date().toLocaleString(),
isLoading: false, //
noMore: false, //
page: 1, //
devices: [
{ id: 1, name: 'Forecasts', description: '预测分析系统', status: 'normal', icon: 'fas fa-chart-line' },
{ id: 2, name: 'Gold', description: '核心处理单元', status: 'warning', icon: 'fas fa-server' },
{ id: 3, name: 'Industries', description: '工业控制系统', status: 'normal', icon: 'fas fa-industry' }
],
//
alerts: [],
//
alertMessageData: [],
tableHeaders: ['设备名称', '设备位置', 'CPU使用率', '内存使用率', '温度', '健康度', '设备运行时长', '采集时间'],
deviceStatus: [
{
id: 1,
name: 'PLC控制系统',
location: '主控室A区',
cpuUsage: 45,
memoryUsage: 62,
temperature: 42,
health: 85,
uptime: '125天8小时',
collectionTime: '2021-10-16 15:20:00'
},
{
id: 2,
name: '数据采集器',
location: '污水处理区',
cpuUsage: 78,
memoryUsage: 85,
temperature: 58,
health: 65,
uptime: '89天12小时',
collectionTime: '2021-10-16 15:22:00'
},
{
id: 3,
name: '监控服务器',
location: '数据中心',
cpuUsage: 32,
memoryUsage: 45,
temperature: 38,
health: 92,
uptime: '210天3小时',
collectionTime: '2021-10-16 15:25:00'
},
{
id: 4,
name: '网络交换机',
location: '通信机房',
cpuUsage: 15,
memoryUsage: 28,
temperature: 35,
health: 95,
uptime: '156天7小时',
collectionTime: '2021-10-16 15:18:00'
}
]
}
},
methods: {
handleSetLineChartData(type) {
this.lineChartData = lineChartData[type]
getCpuStatus(usage) {
if (usage < 50) return 'status-indicator status-good';
if (usage < 80) return 'status-indicator status-warning';
return 'status-indicator status-critical';
},
getLevelColor(level) {
const levelColors = {
0: 'green',
1: 'orange',
2: 'red'
};
return levelColors[level] || 'black'; //
}
}
getMemoryStatus(usage) {
if (usage < 60) return 'status-indicator status-good';
if (usage < 85) return 'status-indicator status-warning';
return 'status-indicator status-critical';
},
getHealthStatus(health) {
if (health >= 80) return 'health-good';
if (health >= 60) return 'health-warning';
return 'health-critical';
},
getstatistic() {
this.loading = true
statistic().then(response => {
this.alerts = response.rows
this.loading = false
}
)
},
getbyEquType() {
this.loading = true
byEquType().then(response => {
this.loading = false
}
)
},
getlistMonitor() {
this.loading = true
listMonitor().then(response => {
this.loading = false
}
)
},
getalertMessageTimes() {
this.loading = true
alertMessageTimes().then(response => {
this.alertMessageData = response.data
this.loading = false
}
)
},
async loadMore() {
console.log("%c 🎧: loadMore -> this.isLoading || this.noMore ", "font-size:16px;background-color:#64b738;color:white;", this.isLoading , this.noMore)
if (this.isLoading || this.noMore) return;
this.isLoading = true;
try {
const res = await statistic({page:this.page}); // API
if (res.rows.length < 10) { // 10
this.noMore = true;
} else {
this.alerts = [...this.alerts, ...res.rows];
this.page++;
}
} catch (error) {
console.error('加载失败:', error);
} finally {
this.isLoading = false;
}
},
},
created() {
// this.getstatistic()
this.getbyEquType()
this.getlistMonitor()
this.getalertMessageTimes()
},
}
</script>
<style lang="scss" scoped>
.dashboard-editor-container {
padding: 32px;
background-color: rgb(240, 242, 245);
position: relative;
.chart-wrapper {
background: #fff;
padding: 16px;
margin-bottom: 32px;
height: 420px;
}
}
@media (max-width:1024px) {
.chart-wrapper {
padding: 8px;
}
}
.dv-scroll-board{
color: #3d3d3d;
}
.card-title {
font-size: 16px;
margin-bottom: 15px;
display: flex;
align-items: center;
color: #3d3d3d;
font-weight: bold;
}
.card-title i {
margin-right: 8px;
font-size: 18px;
}
.data-overview {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.data-item {
flex: 1;
min-width: 30%;
text-align: center;
padding: 15px 10px;
background: #f5f7fa;
border-radius: 8px;
transition: all 0.3s ease;
}
.data-item:hover {
background: #f1f2f4;
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
.data-value {
font-size: 24px;
font-weight: bold;
margin: 10px 0;
color: #3d3d3d;
}
.data-label {
font-size: 14px;
color: #3d3d3d;
}
.alert-list .div0 {
list-style-type: none;
padding: 0;
}
.alert-list .div1 {
display: flex;
justify-content: space-between;
}
.div1{
margin-bottom: 5px;
}
.div2{
padding: 20px 16px;
}
.alert-time, .alert-device-name, .alert-device-location, .alert-message, .alert-status {
flex: 1;
}
.alert-level {
flex: 0.5;
text-align: center;
}
.body {
background-color: #f5f7fa;
color: #333;
line-height: 1.6;
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.header h1 {
color: #2c3e50;
margin-bottom: 10px;
font-size: 28px;
}
.header p {
color: #7f8c8d;
font-size: 16px;
}
.container {
display: flex;
flex-direction: column;
gap: 20px;
}
.top-section {
display: flex;
gap: 20px;
}
.bottom-section {
display: flex;
flex-direction: column;
gap: 20px;
}
.panel {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
}
.card {
background: white;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
padding: 20px;
transition: transform 0.3s ease, box-shadow 0.3s ease;
height: 100%;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.12);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #eaeaea;
}
.card-title {
font-size: 18px;
font-weight: 600;
color: #2c3e50;
display: flex;
align-items: center;
gap: 8px;
}
.card-title i {
color: #3498db;
}
.stats-container {
display: grid;
justify-content: space-between;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
overflow-y: auto;
overflow-x: hidden;
height: 255px;
}
.stat-card {
flex: 1;
background: linear-gradient(135deg, #3498db, #2c3e50);
color: white;
border-radius: 10px;
padding: 12px;
text-align: center;
box-shadow: 0 4px 8px rgba(52, 152, 219, 0.3);
}
.stat-card.warning {
background: linear-gradient(135deg, #e74c3c, #c0392b);
box-shadow: 0 4px 8px rgba(231, 76, 60, 0.3);
}
.stat-card.normal {
background: linear-gradient(135deg, #2ecc71, #27ae60);
box-shadow: 0 4px 8px rgba(46, 204, 113, 0.3);
}
.stat-value {
font-size: 32px;
font-weight: 700;
margin: 10px 0;
}
.stat-label {
font-size: 14px;
opacity: 0.9;
}
.device-list {
list-style: none;
overflow-y: auto;
overflow-x: hidden;
max-height: 255px;
}
.device-item {
display: flex;
align-items: center;
padding: 12px 15px;
margin-bottom: 10px;
background: #f8f9fa;
border-radius: 8px;
border-left: 4px solid #3498db;
transition: all 0.2s;
}
.device-item:hover {
background: #edf2f7;
transform: translateX(5px);
}
.device-item.warning {
border-left-color: #e74c3c;
}
.device-item.normal {
border-left-color: #2ecc71;
}
.device-icon {
width: 40px;
height: 40px;
background: #3498db;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
color: white;
}
.device-item.warning .device-icon {
background: #e74c3c;
}
.device-item.normal .device-icon {
background: #2ecc71;
}
.device-info {
flex: 1;
}
.device-name {
font-weight: 600;
margin-bottom: 5px;
}
.device-details {
font-size: 13px;
color: #666;
}
.alert-badge {
background: #e74c3c;
color: white;
padding: 3px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
}
.normal-badge {
background: #2ecc71;
color: white;
padding: 3px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
}
.table-container {
overflow-x: auto;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
table {
width: 100%;
border-collapse: collapse;
background: white;
}
th {
background: #2c3e50;
color: white;
padding: 15px 12px;
text-align: left;
font-weight: 600;
}
td {
padding: 12px;
border-bottom: 1px solid #eaeaea;
}
tr:hover {
background-color: #f5f7fa;
}
.status-indicator {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 5px;
}
.status-good {
background-color: #2ecc71;
}
.status-warning {
background-color: #f39c12;
}
.status-critical {
background-color: #e74c3c;
}
.health-bar {
height: 6px;
background: #ecf0f1;
border-radius: 3px;
overflow: hidden;
}
.health-fill {
height: 100%;
border-radius: 3px;
}
.health-good {
background: #2ecc71;
width: 85%;
}
.health-warning {
background: #f39c12;
width: 65%;
}
.health-critical {
background: #e74c3c;
width: 40%;
}
.full-width {
width: 100%;
}
@media (max-width: 1024px) {
.top-section {
flex-direction: column;
}
.stats-container {
flex-direction: column;
}
}
</style>

@ -0,0 +1,185 @@
<template>
<div class="dashboard">
<h1>唐山烟草智能网络设备运维与问答系统</h1>
<el-row :gutter="20">
<!-- 设备状态监控 -->
<el-col :span="12">
<el-card>
<h2>设备状态监控</h2>
<!-- 这里可以添加设备状态监控的具体内容例如表格或图表 -->
<el-table :data="deviceStatusData" style="width: 100%">
<el-table-column prop="name" label="设备名称"></el-table-column>
<el-table-column prop="location" label="设备位置"></el-table-column>
<el-table-column prop="cpuUsage" label="CPU使用率"></el-table-column>
<el-table-column prop="memoryUsage" label="内存使用率"></el-table-column>
<el-table-column prop="status" label="状态">
<template slot-scope="scope">
<el-tag :type="scope.row.status === '正常' ? 'success' : 'danger'">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<!-- 设备状态统计图表 -->
<el-col :span="12">
<el-card>
<h2>检测设备信息 (按状态统计饼状图)</h2>
<!-- 这里可以使用echarts或其他图表库来展示饼状图 -->
<div id="statusChart" style="width: 100%; height: 300px;"></div>
</el-card>
</el-col>
<el-col :span="12">
<el-card>
<h2>检测设备信息 (按设备类型饼状图)</h2>
<div id="typeChart" style="width: 100%; height: 300px;"></div>
</el-card>
</el-col>
<!-- 设备预警信息 -->
<el-col :span="12">
<el-card>
<h2>设备预警信息</h2>
<el-table :data="alertData" style="width: 100%">
<el-table-column prop="time" label="预警时间"></el-table-column>
<el-table-column prop="device" label="设备名称"></el-table-column>
<el-table-column prop="location" label="设备位置"></el-table-column>
<el-table-column prop="level" label="预警等级">
<template slot-scope="scope">
<el-tag :type="getTagType(scope.row.level)">
{{ scope.row.level }}
</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<!-- 预警信息统计 -->
<el-col :span="12">
<el-card>
<h2>预警信息统计</h2>
<div id="alertStatsChart" style="width: 100%; height: 300px;"></div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import * as echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
export default {
data() {
return {
deviceStatusData: [
//
{ name: '设备1', location: '位置1', cpuUsage: '30%', memoryUsage: '40%', status: '正常' },
{ name: '设备2', location: '位置2', cpuUsage: '70%', memoryUsage: '80%', status: '异常' },
],
alertData: [
//
{ time: '2023-10-01 10:00:00', device: '设备2', location: '位置2', level: '高' },
{ time: '2023-10-01 11:00:00', device: '设备3', location: '位置3', level: '中' },
],
};
},
mounted() {
this.initCharts();
},
methods: {
getTagType(level) {
const types = { '高': 'danger', '中': 'warning', '低': 'success' };
return types[level] || 'info';
},
initCharts() {
//
const statusChart = echarts.init(document.getElementById('statusChart'));
statusChart.setOption({
title: { text: '设备状态统计', subtext: '按状态', left: 'center' },
tooltip: { trigger: 'item' },
series: [
{
name: '设备状态',
type: 'pie',
radius: '50%',
data: [
{ value: 44, name: '自主房屋' },
{ value: 33, name: '出租房屋' },
{ value: 11, name: '空置房屋' },
{ value: 11, name: '其他' },
],
},
],
});
//
const typeChart = echarts.init(document.getElementById('typeChart'));
typeChart.setOption({
title: { text: '设备类型统计', subtext: '按设备类型', left: 'center' },
tooltip: { trigger: 'item' },
series: [
{
name: '设备类型',
type: 'pie',
radius: '50%',
data: [
{ value: 44, name: '自主房屋' },
{ value: 33, name: '出租房屋' },
{ value: 11, name: '空置房屋' },
{ value: 11, name: '其他' },
],
},
],
});
//
const alertStatsChart = echarts.init(document.getElementById('alertStatsChart'));
alertStatsChart.setOption({
title: { text: '预警信息统计', left: 'center' },
tooltip: {},
radar: {
indicator: [
{ name: '火警类', max: 500 },
{ name: '冲禁类', max: 500 },
{ name: '灾害', max: 500 },
{ name: '群体性', max: 500 },
{ name: '行政类', max: 500 },
{ name: '交通类', max: 500 },
{ name: '重大', max: 500 },
],
},
series: [{
name: '预警统计',
type: 'radar',
data: [
{
value: [75, 452, 64, 94, 44, 0, 29],
name: '预警次数',
},
],
}],
});
},
},
};
</script>
<style>
.dashboard {
padding: 20px;
background-color: #f0f2f5;
min-height: 100vh;
}
h1, h2 {
text-align: center;
}
.el-card {
margin-bottom: 20px;
}
</style>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save