|
|
@@ -5,49 +5,34 @@ import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
-import com.zksy.WaterSupply.MonitorAlarm.domain.AlarmAudit;
|
|
|
-import com.zksy.WaterSupply.MonitorAlarm.dto.in.AlarmAuditInDTO;
|
|
|
-import com.zksy.WaterSupply.MonitorAlarm.dto.in.AlarmDispatchInDTO;
|
|
|
-import com.zksy.WaterSupply.MonitorAlarm.dto.out.AlarmAuditOutDTO;
|
|
|
import com.zksy.WaterSupply.MonitorAlarm.dto.out.AlarmDashboardOutDTO;
|
|
|
-import com.zksy.WaterSupply.MonitorAlarm.dto.out.AlarmFlowOutDTO;
|
|
|
import com.zksy.WaterSupply.MonitorAlarm.dto.out.AlarmMapPointOutDTO;
|
|
|
-import com.zksy.WaterSupply.MonitorAlarm.dto.out.AlarmAuditOrderStatVO;
|
|
|
import com.zksy.WaterSupply.MonitorAlarm.dto.out.AlarmStatsOutDTO;
|
|
|
import com.zksy.WaterSupply.MonitorAlarm.dto.out.WaterAlarmOutDTO;
|
|
|
-import com.zksy.WaterSupply.MonitorAlarm.mapper.AlarmAuditMapper;
|
|
|
import com.zksy.WaterSupply.MonitorAlarm.service.IWaterSupplyAlarmService;
|
|
|
import com.zksy.base.service.impl.WaterSupplyQueryService;
|
|
|
import com.zksy.base.alarm.domain.AlarmData;
|
|
|
-import com.zksy.base.alarm.service.AlarmClearService;
|
|
|
+import com.zksy.base.alarm.enums.AlarmAuditStatusEnum;
|
|
|
+import com.zksy.base.alarm.enums.AlarmDisplayStatusEnum;
|
|
|
+import com.zksy.base.alarm.enums.AlarmLevelEnum;
|
|
|
+import com.zksy.base.alarm.enums.AlarmRecordStatusEnum;
|
|
|
+import com.zksy.ops.enums.WorkOrderStatusEnum;
|
|
|
import com.zksy.base.alarm.service.AlarmDataService;
|
|
|
import com.zksy.base.domain.EquipmentBase;
|
|
|
import com.zksy.base.domain.EquipmentStatus;
|
|
|
import com.zksy.base.domain.EquipmentType;
|
|
|
import com.zksy.base.mapper.EquipmentTypeMapper;
|
|
|
import com.zksy.ops.domain.WorkOrder;
|
|
|
-import com.zksy.ops.domain.WorkOrderLog;
|
|
|
-import com.zksy.ops.domain.vo.WorkOrderLogVO;
|
|
|
-import com.zksy.ops.domain.vo.WorkOrderVO;
|
|
|
-import com.zksy.ops.enums.WorkOrderLogOperTypeEnum;
|
|
|
-import com.zksy.ops.enums.WorkOrderStatusEnum;
|
|
|
import com.zksy.base.mapper.EquipmentBaseMapper;
|
|
|
-import com.zksy.ops.mapper.WorkOrderLogMapper;
|
|
|
import com.zksy.ops.mapper.WorkOrderMapper;
|
|
|
-import com.zksy.common.core.domain.model.LoginUser;
|
|
|
import com.zksy.common.exception.ServiceException;
|
|
|
-import com.zksy.common.utils.SecurityUtils;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
-import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
-import java.math.BigDecimal;
|
|
|
import java.time.LocalDate;
|
|
|
import java.time.LocalDateTime;
|
|
|
-import java.time.format.DateTimeFormatter;
|
|
|
import java.util.ArrayList;
|
|
|
-import java.util.Arrays;
|
|
|
import java.util.Collection;
|
|
|
import java.util.Collections;
|
|
|
import java.util.Comparator;
|
|
|
@@ -55,7 +40,6 @@ import java.util.LinkedHashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Objects;
|
|
|
-import java.util.Random;
|
|
|
import java.util.Set;
|
|
|
import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
|
@@ -67,13 +51,10 @@ import java.util.stream.Collectors;
|
|
|
@Service
|
|
|
public class WaterSupplyAlarmServiceImpl implements IWaterSupplyAlarmService {
|
|
|
|
|
|
- private static final DateTimeFormatter ORDER_NO_FMT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
|
|
|
|
|
@Autowired
|
|
|
private AlarmDataService alarmDataService;
|
|
|
|
|
|
- @Autowired
|
|
|
- private AlarmClearService alarmClearService;
|
|
|
|
|
|
@Autowired
|
|
|
private WaterSupplyQueryService waterSupplyQueryService;
|
|
|
@@ -84,44 +65,15 @@ public class WaterSupplyAlarmServiceImpl implements IWaterSupplyAlarmService {
|
|
|
@Autowired
|
|
|
private WorkOrderMapper workOrderMapper;
|
|
|
|
|
|
- @Autowired
|
|
|
- private WorkOrderLogMapper workOrderLogMapper;
|
|
|
|
|
|
- @Autowired
|
|
|
- private AlarmAuditMapper alarmAuditMapper;
|
|
|
|
|
|
@Autowired
|
|
|
private EquipmentTypeMapper equipmentTypeMapper;
|
|
|
|
|
|
/** 报警展示状态:1-待审核 2-已转工单 3-已解除 */
|
|
|
- private static final int DISPLAY_PENDING_AUDIT = 1;
|
|
|
- private static final int DISPLAY_TRANSFERRED = 2;
|
|
|
- private static final int DISPLAY_RELEASED = 3;
|
|
|
-
|
|
|
- /** 审核动作:1-转工单 2-误报解除(报警审核页仅提供这两个动作) */
|
|
|
- private static final int AUDIT_ACTION_TRANSFER = 1;
|
|
|
- private static final int AUDIT_ACTION_FALSE_ALARM_RELEASE = 2;
|
|
|
-
|
|
|
- /**
|
|
|
- * 审核页计数条分组。状态码一律取自权威枚举 WorkOrderStatusEnum(ADR-0010),
|
|
|
- * 不写字面量,也不以前端字典为准;未办结工单集合直接用 activeCodes()。
|
|
|
- */
|
|
|
- private static final List<Integer> GROUP_PENDING = Arrays.asList(
|
|
|
- WorkOrderStatusEnum.PENDING_DISPATCH.getCode(),
|
|
|
- WorkOrderStatusEnum.PENDING_ACCEPT.getCode());
|
|
|
- private static final List<Integer> GROUP_PROCESSING = Arrays.asList(
|
|
|
- WorkOrderStatusEnum.ACCEPTED.getCode(),
|
|
|
- WorkOrderStatusEnum.PROCESSING.getCode(),
|
|
|
- WorkOrderStatusEnum.DELAYING.getCode());
|
|
|
- private static final List<Integer> GROUP_VERIFYING = Collections.singletonList(
|
|
|
- WorkOrderStatusEnum.PENDING_VERIFY.getCode());
|
|
|
- private static final List<Integer> GROUP_FINISHED = WorkOrderStatusEnum.finishedCodes();
|
|
|
-
|
|
|
- /** 审核结果:1-属实/审核通过 2-误报/解除报警 */
|
|
|
- private static final int AUDIT_RESULT_FALSE_ALARM = 2;
|
|
|
-
|
|
|
- private static final String SAME_TYPE_ORDER_EXISTS =
|
|
|
- "该设备同一报警类型已存在未结束的故障维修工单,不能重复创建";
|
|
|
+ private static final int DISPLAY_PENDING_AUDIT = AlarmDisplayStatusEnum.PENDING.getCode();
|
|
|
+ private static final int DISPLAY_TRANSFERRED = AlarmDisplayStatusEnum.TRANSFERRED.getCode();
|
|
|
+ private static final int DISPLAY_RELEASED = AlarmDisplayStatusEnum.RELEASED.getCode();
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
// 供水设备范围解析
|
|
|
@@ -333,7 +285,6 @@ public class WaterSupplyAlarmServiceImpl implements IWaterSupplyAlarmService {
|
|
|
.filter(StrUtil::isNotBlank)
|
|
|
.collect(Collectors.toSet()));
|
|
|
Map<String, WorkOrder> orderMap = loadWorkOrderMapByAlarmIds(alarmIds);
|
|
|
- Map<String, AlarmAudit> latestAuditMap = loadLatestAuditMap(alarmIds);
|
|
|
Map<String, EquipmentStatus> statusMap = loadStatusMap(eqMap.values());
|
|
|
List<WaterAlarmOutDTO> vos = new ArrayList<>();
|
|
|
for (AlarmData alarm : alarms) {
|
|
|
@@ -359,10 +310,10 @@ public class WaterSupplyAlarmServiceImpl implements IWaterSupplyAlarmService {
|
|
|
vo.setOrderNo(order.getOrderNo());
|
|
|
vo.setOrderStatus(order.getOrderStatus());
|
|
|
}
|
|
|
- int deviceAlarm = resolveDeviceAlarmStatus(alarm, eq, statusMap, latestAuditMap.get(alarm.getId()));
|
|
|
+ int deviceAlarm = resolveDeviceAlarmStatus(alarm, eq, statusMap);
|
|
|
vo.setDeviceAlarmStatus(deviceAlarm);
|
|
|
vo.setDeviceAlarmStatusText(deviceAlarm == 1 ? "报警中" : "正常");
|
|
|
- int display = resolveDisplayStatus(alarm, order, latestAuditMap.get(alarm.getId()));
|
|
|
+ int display = resolveDisplayStatus(alarm, order);
|
|
|
vo.setDisplayStatus(display);
|
|
|
vo.setDisplayStatusText(displayStatusText(display));
|
|
|
vos.add(vo);
|
|
|
@@ -371,62 +322,39 @@ public class WaterSupplyAlarmServiceImpl implements IWaterSupplyAlarmService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 设备报警状态:以设备状态表为准;无状态记录时回退到报警记录是否未处理,
|
|
|
- * 但经审核判定为误报解除的报警不再视为设备报警中。
|
|
|
+ * 设备报警状态以设备状态表为准;无记录时回退到报警记录状态,不从审核结果推断设备恢复。
|
|
|
*/
|
|
|
private int resolveDeviceAlarmStatus(AlarmData alarm, EquipmentBase eq,
|
|
|
- Map<String, EquipmentStatus> statusMap, AlarmAudit audit) {
|
|
|
+ Map<String, EquipmentStatus> statusMap) {
|
|
|
if (eq != null && eq.getEquipmentId() != null) {
|
|
|
EquipmentStatus status = statusMap.get(eq.getEquipmentId());
|
|
|
if (status != null && status.getAlarmStatus() != null) {
|
|
|
return status.getAlarmStatus();
|
|
|
}
|
|
|
}
|
|
|
- if (audit != null && (Integer.valueOf(2).equals(audit.getAuditResult())
|
|
|
- || Integer.valueOf(2).equals(audit.getAuditAction()))) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
return alarm.getAlarmStatus() != null && alarm.getAlarmStatus() == 0 ? 1 : 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 报警展示状态推导:
|
|
|
- * 关联工单未取消 -> 已转工单;否则报警记录已处理或最新审核为误报 -> 已解除;其余 -> 待审核。
|
|
|
- * 工单已取消代表处置已撤销,按报警事实自身归档为已解除,展示口径由后端统一。
|
|
|
+ * 关联工单未取消 -> 已转工单;报警已处理 -> 已解除;误报审核 -> 误报警。
|
|
|
+ * 已确认的报警即使工单取消,也不能重新显示成待审核或已恢复。
|
|
|
*/
|
|
|
- private int resolveDisplayStatus(AlarmData alarm, WorkOrder order, AlarmAudit audit) {
|
|
|
- boolean orderAlive = order != null && !Integer.valueOf(7).equals(order.getOrderStatus());
|
|
|
- if (orderAlive) {
|
|
|
+ private int resolveDisplayStatus(AlarmData alarm, WorkOrder order) {
|
|
|
+ boolean orderAlive = order != null && !WorkOrderStatusEnum.CANCELLED.getCode().equals(order.getOrderStatus());
|
|
|
+ if (orderAlive || Objects.equals(alarm.getAuditStatus(), AlarmAuditStatusEnum.CONFIRMED.getCode())) {
|
|
|
return DISPLAY_TRANSFERRED;
|
|
|
}
|
|
|
- boolean alarmHandled = alarm.getAlarmStatus() != null && alarm.getAlarmStatus() == 1;
|
|
|
- boolean falseAlarm = audit != null && Integer.valueOf(2).equals(audit.getAuditResult());
|
|
|
- return alarmHandled || falseAlarm ? DISPLAY_RELEASED : DISPLAY_PENDING_AUDIT;
|
|
|
+ boolean alarmHandled = Objects.equals(alarm.getAlarmStatus(), AlarmRecordStatusEnum.HANDLED.getCode());
|
|
|
+ boolean falseAlarm = Objects.equals(alarm.getAuditStatus(), AlarmAuditStatusEnum.FALSE_ALARM.getCode());
|
|
|
+ if (alarmHandled) return DISPLAY_RELEASED;
|
|
|
+ if (falseAlarm) return AlarmDisplayStatusEnum.FALSE_ALARM.getCode();
|
|
|
+ return DISPLAY_PENDING_AUDIT;
|
|
|
}
|
|
|
|
|
|
private String displayStatusText(int displayStatus) {
|
|
|
- switch (displayStatus) {
|
|
|
- case DISPLAY_TRANSFERRED:
|
|
|
- return "已转工单";
|
|
|
- case DISPLAY_RELEASED:
|
|
|
- return "已解除";
|
|
|
- default:
|
|
|
- return "待审核";
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 报警ID -> 最新审核记录
|
|
|
- */
|
|
|
- private Map<String, AlarmAudit> loadLatestAuditMap(List<String> alarmIds) {
|
|
|
- if (CollUtil.isEmpty(alarmIds)) {
|
|
|
- return Collections.emptyMap();
|
|
|
- }
|
|
|
- List<AlarmAudit> audits = alarmAuditMapper.selectList(new LambdaQueryWrapper<AlarmAudit>()
|
|
|
- .in(AlarmAudit::getAlarmId, alarmIds)
|
|
|
- .orderByDesc(AlarmAudit::getAuditId));
|
|
|
- return audits.stream()
|
|
|
- .collect(Collectors.toMap(AlarmAudit::getAlarmId, Function.identity(), (a, b) -> a));
|
|
|
+ AlarmDisplayStatusEnum value = AlarmDisplayStatusEnum.fromCode(displayStatus);
|
|
|
+ return value == null ? "未知状态" : value.getLabel();
|
|
|
}
|
|
|
|
|
|
private Map<String, EquipmentStatus> loadStatusMap(Collection<EquipmentBase> devices) {
|
|
|
@@ -627,366 +555,8 @@ public class WaterSupplyAlarmServiceImpl implements IWaterSupplyAlarmService {
|
|
|
}
|
|
|
|
|
|
private String formatAlarmLevel(Integer alarmLevel) {
|
|
|
- if (alarmLevel == null) {
|
|
|
- return "";
|
|
|
- }
|
|
|
- switch (alarmLevel) {
|
|
|
- case 1:
|
|
|
- return "一级报警";
|
|
|
- case 2:
|
|
|
- return "二级报警";
|
|
|
- case 3:
|
|
|
- return "三级报警";
|
|
|
- case 4:
|
|
|
- return "四级报警";
|
|
|
- default:
|
|
|
- return "报警";
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // ------------------------------------------------------------------
|
|
|
- // 处理 / 派发工单
|
|
|
- // ------------------------------------------------------------------
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean resolveAlarm(String alarmId, String handleRemark) {
|
|
|
- AlarmData alarm = alarmDataService.getById(alarmId);
|
|
|
- if (alarm == null) {
|
|
|
- throw new ServiceException("报警信息不存在");
|
|
|
- }
|
|
|
- alarm.setAlarmStatus(1);
|
|
|
- alarm.setHandleTime(LocalDateTime.now());
|
|
|
- alarm.setHandleUser(currentUserName());
|
|
|
- alarm.setHandleRemark(StrUtil.blankToDefault(handleRemark, "标记已处理"));
|
|
|
- alarm.setUpdateTime(LocalDateTime.now());
|
|
|
- return alarmDataService.updateById(alarm);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- @Transactional(rollbackFor = Exception.class)
|
|
|
- public boolean dispatchToWorkOrder(AlarmDispatchInDTO inDTO) {
|
|
|
- if (inDTO == null || StrUtil.isBlank(inDTO.getAlarmId())) {
|
|
|
- throw new ServiceException("报警ID不能为空");
|
|
|
- }
|
|
|
- AlarmData alarm = alarmDataService.getById(inDTO.getAlarmId());
|
|
|
- if (alarm == null) {
|
|
|
- throw new ServiceException("报警信息不存在");
|
|
|
- }
|
|
|
-
|
|
|
- // 同类报警工单位一性:同设备同报警类型只允许一张未办结工单
|
|
|
- if (alarm.getOrderId() != null) {
|
|
|
- if (workOrderMapper.selectById(alarm.getOrderId()) != null) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- throw new ServiceException("报警关联的工单不存在,请先检查关联数据");
|
|
|
- }
|
|
|
- assertNoUnfinishedSameTypeOrder(alarm);
|
|
|
-
|
|
|
- // 工单只保存设备主键;设备编码由 equipment_base 关联查询。
|
|
|
- EquipmentBase equipment = alarm.getDeviceCode() == null ? null
|
|
|
- : equipmentBaseMapper.selectOne(new LambdaQueryWrapper<EquipmentBase>()
|
|
|
- .eq(EquipmentBase::getEquipmentCode, alarm.getDeviceCode())
|
|
|
- .last("LIMIT 1"));
|
|
|
-
|
|
|
- WorkOrder workOrder = new WorkOrder();
|
|
|
- workOrder.setOrderNo(generateOrderNo());
|
|
|
- if (equipment == null) {
|
|
|
- throw new ServiceException("报警设备未关联设备档案,无法创建工单");
|
|
|
- }
|
|
|
- workOrder.setDeviceId(equipment.getEquipmentId());
|
|
|
- workOrder.setOrderLevel(inDTO.getOrderLevel() == null
|
|
|
- ? mapAlarmLevelToOrderLevel(alarm.getAlarmLevel()) : inDTO.getOrderLevel());
|
|
|
- workOrder.setOrderDesc(StrUtil.isNotBlank(inDTO.getOrderDesc()) ? inDTO.getOrderDesc()
|
|
|
- : buildDefaultOrderDesc(alarm));
|
|
|
- workOrder.setDeptId(inDTO.getDeptId());
|
|
|
- // 与统一工单手动创建路径一致:数据按部门隔离,缺省时归属当前用户部门,
|
|
|
- // 否则部门范围过滤会让这张报警工单在统一工单页查不到,闭环断裂。
|
|
|
- if (workOrder.getDeptId() == null) {
|
|
|
- workOrder.setDeptId(currentDeptId());
|
|
|
- }
|
|
|
- workOrder.setPlanFinishTime(inDTO.getPlanFinishTime());
|
|
|
- workOrder.setOrderStatus(WorkOrderStatusEnum.PENDING_DISPATCH.getCode());
|
|
|
- workOrder.setCreateTime(new java.util.Date());
|
|
|
- workOrder.setUpdateTime(new java.util.Date());
|
|
|
- workOrderMapper.insert(workOrder);
|
|
|
- alarm.setOrderId(workOrder.getOrderId());
|
|
|
-
|
|
|
- // 写工单操作日志(0-创建工单)
|
|
|
- WorkOrderLog workOrderLog = new WorkOrderLog();
|
|
|
- workOrderLog.setOrderId(workOrder.getOrderId());
|
|
|
- workOrderLog.setOperType(0);
|
|
|
- workOrderLog.setOperDesc("由供水监测报警[" + alarm.getWarningType() + "]派发工单:" + workOrder.getOrderNo());
|
|
|
- workOrderLog.setOperUserId(currentUserId());
|
|
|
- workOrderLog.setOperUserName(currentUserName());
|
|
|
- workOrderLog.setOperTime(new java.util.Date());
|
|
|
- workOrderLogMapper.insert(workOrderLog);
|
|
|
-
|
|
|
- // 回写报警处理信息
|
|
|
- alarm.setAlarmStatus(1);
|
|
|
- alarm.setHandleTime(LocalDateTime.now());
|
|
|
- alarm.setHandleUser(currentUserName());
|
|
|
- alarm.setHandleRemark("已派发工单:" + workOrder.getOrderNo());
|
|
|
- alarm.setUpdateTime(LocalDateTime.now());
|
|
|
- if (!alarmDataService.update(alarm, new LambdaQueryWrapper<AlarmData>()
|
|
|
- .eq(AlarmData::getId, alarm.getId()).isNull(AlarmData::getOrderId))) {
|
|
|
- throw new ServiceException("报警已关联工单或已被删除,请刷新后重试");
|
|
|
- }
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 报警等级 -> 工单优先级:1级→紧急(0),2/3级→一般(1),4级→低(2)
|
|
|
- */
|
|
|
- private Integer mapAlarmLevelToOrderLevel(Integer alarmLevel) {
|
|
|
- if (alarmLevel == null || alarmLevel == 1) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
- if (alarmLevel == 4) {
|
|
|
- return 2;
|
|
|
- }
|
|
|
- return 1;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 报警审核页工单状态计数:只统计供水设备且由报警生成的工单。
|
|
|
- *
|
|
|
- * <p>分组口径以权威枚举 WorkOrderStatusEnum 为准(ADR-0010),前端字典只是同一口径的镜像,
|
|
|
- * 不作为真相源,避免同一工单在两个页面被算成不同状态。</p>
|
|
|
- */
|
|
|
- @Override
|
|
|
- public AlarmAuditOrderStatVO getAuditOrderStats() {
|
|
|
- AlarmAuditOrderStatVO stats = new AlarmAuditOrderStatVO();
|
|
|
- Set<String> waterDeviceIds = waterSupplyQueryService.waterDeviceIds();
|
|
|
- if (waterDeviceIds.isEmpty()) {
|
|
|
- return stats;
|
|
|
- }
|
|
|
- // 复用统一工单既有的状态聚合查询(返回 status / cnt),不再自造 group by SQL 片段
|
|
|
- List<Map<String, Object>> rows = workOrderMapper.countByStatus(new LambdaQueryWrapper<WorkOrder>()
|
|
|
- .exists("SELECT 1 FROM app_user.alarm_data a WHERE a.order_id = app_user.work_order.order_id")
|
|
|
- .in(WorkOrder::getDeviceId, waterDeviceIds));
|
|
|
- long total = 0L;
|
|
|
- for (Map<String, Object> row : rows) {
|
|
|
- Long count = asLong(row.get("cnt"));
|
|
|
- Integer status = asInt(row.get("status"));
|
|
|
- if (count == null || count == 0L || status == null || !WorkOrderStatusEnum.isValid(status)) {
|
|
|
- // 非法/未知状态既不计入任何分组,也不计入总数,保证「全部 = 四个分组之和」
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (GROUP_PENDING.contains(status)) {
|
|
|
- stats.setPendingCount(stats.getPendingCount() + count);
|
|
|
- } else if (GROUP_PROCESSING.contains(status)) {
|
|
|
- stats.setProcessingCount(stats.getProcessingCount() + count);
|
|
|
- } else if (GROUP_VERIFYING.contains(status)) {
|
|
|
- stats.setVerifyingCount(stats.getVerifyingCount() + count);
|
|
|
- } else if (GROUP_FINISHED.contains(status)) {
|
|
|
- stats.setFinishedCount(stats.getFinishedCount() + count);
|
|
|
- }
|
|
|
- total += count;
|
|
|
- }
|
|
|
- stats.setTotal(total);
|
|
|
- return stats;
|
|
|
- }
|
|
|
-
|
|
|
- private Long asLong(Object value) {
|
|
|
- return value instanceof Number ? ((Number) value).longValue() : null;
|
|
|
- }
|
|
|
-
|
|
|
- private Integer asInt(Object value) {
|
|
|
- return value instanceof Number ? ((Number) value).intValue() : null;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 同类报警工单位一性:同一设备、同一报警类型下,只允许存在一张未办结的故障维修工单。
|
|
|
- *
|
|
|
- * <p>工单流程重构后报警与工单通过 alarm_data.order_id 关联;因此唯一性按
|
|
|
- * “同设备 + 同报警类型的报警记录集合 + 未办结工单”判定,
|
|
|
- * 而不是只看当前这一条报警。</p>
|
|
|
- */
|
|
|
- private void assertNoUnfinishedSameTypeOrder(AlarmData alarm) {
|
|
|
- if (StrUtil.isBlank(alarm.getDeviceCode()) || StrUtil.isBlank(alarm.getWarningType())) {
|
|
|
- throw new ServiceException("报警记录缺少设备编码或报警类型,无法判定同类工单");
|
|
|
- }
|
|
|
- List<Long> orderIds = alarmDataService.list(new LambdaQueryWrapper<AlarmData>()
|
|
|
- .select(AlarmData::getOrderId)
|
|
|
- .eq(AlarmData::getDeviceCode, alarm.getDeviceCode())
|
|
|
- .eq(AlarmData::getWarningType, alarm.getWarningType())
|
|
|
- .isNotNull(AlarmData::getOrderId)).stream()
|
|
|
- .map(AlarmData::getOrderId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
|
|
- if (orderIds.isEmpty()) return;
|
|
|
- long unfinished = workOrderMapper.selectCount(new LambdaQueryWrapper<WorkOrder>()
|
|
|
- .in(WorkOrder::getOrderId, orderIds)
|
|
|
- .in(WorkOrder::getOrderStatus, WorkOrderStatusEnum.activeCodes()));
|
|
|
- if (unfinished > 0) {
|
|
|
- throw new ServiceException(SAME_TYPE_ORDER_EXISTS);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 审核动作白名单:只允许“转工单”与“误报解除”。
|
|
|
- */
|
|
|
- private void validateAuditAction(Integer auditAction) {
|
|
|
- if (auditAction == null) {
|
|
|
- throw new ServiceException("审核动作不能为空");
|
|
|
- }
|
|
|
- if (auditAction != AUDIT_ACTION_TRANSFER && auditAction != AUDIT_ACTION_FALSE_ALARM_RELEASE) {
|
|
|
- throw new ServiceException("审核动作仅支持 1-转工单 或 2-误报解除");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 是否为“误报解除”:动作=2 或 结果=2 都按解除处理,不创建工单。
|
|
|
- */
|
|
|
- private boolean isFalseAlarmRelease(AlarmAuditInDTO inDTO) {
|
|
|
- return Objects.equals(inDTO.getAuditResult(), AUDIT_RESULT_FALSE_ALARM)
|
|
|
- || Objects.equals(inDTO.getAuditAction(), AUDIT_ACTION_FALSE_ALARM_RELEASE);
|
|
|
- }
|
|
|
-
|
|
|
- private String buildDefaultOrderDesc(AlarmData alarm) {
|
|
|
- StringBuilder sb = new StringBuilder();
|
|
|
- sb.append(StrUtil.blankToDefault(alarm.getWarningType(), "监测报警"));
|
|
|
- sb.append(",当前值:").append(alarm.getActualValue() == null ? "-" : alarm.getActualValue().toPlainString());
|
|
|
- if (alarm.getMinValue() != null || alarm.getMaxValue() != null) {
|
|
|
- sb.append(",阈值范围:").append(alarm.getMinValue() == null ? "-" : alarm.getMinValue().toPlainString())
|
|
|
- .append("~").append(alarm.getMaxValue() == null ? "-" : alarm.getMaxValue().toPlainString());
|
|
|
- }
|
|
|
- sb.append(",请及时现场核实处理");
|
|
|
- return sb.toString();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 生成工单编号:WO + yyyyMMddHHmmss + 4位随机数
|
|
|
- */
|
|
|
- private String generateOrderNo() {
|
|
|
- return "WO" + LocalDateTime.now().format(ORDER_NO_FMT)
|
|
|
- + String.format("%04d", new Random().nextInt(10000));
|
|
|
- }
|
|
|
-
|
|
|
- // ------------------------------------------------------------------
|
|
|
- // 报警审核 / 全流程跟踪
|
|
|
- // ------------------------------------------------------------------
|
|
|
-
|
|
|
- @Override
|
|
|
- @Transactional(rollbackFor = Exception.class)
|
|
|
- public AlarmAuditOutDTO auditAlarm(AlarmAuditInDTO inDTO) {
|
|
|
- if (inDTO == null || StrUtil.isBlank(inDTO.getAlarmId())) {
|
|
|
- throw new ServiceException("报警ID不能为空");
|
|
|
- }
|
|
|
- validateAuditAction(inDTO.getAuditAction());
|
|
|
- if (inDTO.getAuditResult() == null) {
|
|
|
- throw new ServiceException("审核结果不能为空");
|
|
|
- }
|
|
|
- AlarmData alarm = alarmDataService.getById(inDTO.getAlarmId());
|
|
|
- if (alarm == null) {
|
|
|
- throw new ServiceException("报警信息不存在");
|
|
|
- }
|
|
|
-
|
|
|
- // 转工单分支先校验同类工单位一性,避免失败后留下半截审核记录
|
|
|
- if (!isFalseAlarmRelease(inDTO)) {
|
|
|
- assertNoUnfinishedSameTypeOrder(alarm);
|
|
|
- }
|
|
|
-
|
|
|
- AlarmAudit audit = new AlarmAudit();
|
|
|
- audit.setAlarmId(inDTO.getAlarmId());
|
|
|
- audit.setAuditAction(inDTO.getAuditAction());
|
|
|
- audit.setAuditResult(inDTO.getAuditResult());
|
|
|
- audit.setAuditOpinion(inDTO.getAuditOpinion());
|
|
|
- audit.setAttachUrl(inDTO.getAttachUrl());
|
|
|
- audit.setAuditUserId(currentUserId());
|
|
|
- audit.setAuditUserName(currentUserName());
|
|
|
- audit.setAuditTime(LocalDateTime.now());
|
|
|
- audit.setCreateTime(LocalDateTime.now());
|
|
|
- audit.setUpdateTime(LocalDateTime.now());
|
|
|
- alarmAuditMapper.insert(audit);
|
|
|
-
|
|
|
- // 审核结果=误报 或 动作=误报解除 时,直接关闭报警,且不创建工单
|
|
|
- boolean releaseAlarm = isFalseAlarmRelease(inDTO);
|
|
|
- if (releaseAlarm) {
|
|
|
- alarm.setAlarmStatus(1);
|
|
|
- alarm.setHandleTime(LocalDateTime.now());
|
|
|
- alarm.setHandleUser(audit.getAuditUserName());
|
|
|
- alarm.setHandleRemark("误报解除:" + StrUtil.blankToDefault(inDTO.getAuditOpinion(), "经审核确认为误报"));
|
|
|
- alarm.setUpdateTime(LocalDateTime.now());
|
|
|
- alarmDataService.updateById(alarm);
|
|
|
- // 误报解除只是触发清警复核的时机:是否清警由运行系统汇总有效报警原因后决定
|
|
|
- // (ADR-0002)。仍有其他有效原因时复核会保留设备报警状态(#51)。
|
|
|
- alarmClearService.review(alarm.getDeviceCode(), "误报解除");
|
|
|
- } else {
|
|
|
- // 审核通过即上传至运维工单,工单默认待派单状态
|
|
|
- AlarmDispatchInDTO dispatch = new AlarmDispatchInDTO();
|
|
|
- dispatch.setAlarmId(alarm.getId());
|
|
|
- dispatch.setOrderLevel(mapAlarmLevelToOrderLevel(alarm.getAlarmLevel()));
|
|
|
- dispatch.setOrderDesc(StrUtil.isBlank(inDTO.getAuditOpinion())
|
|
|
- ? null : inDTO.getAuditOpinion());
|
|
|
- dispatchToWorkOrder(dispatch);
|
|
|
- }
|
|
|
- return toAuditOutDTO(audit);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public List<AlarmAuditOutDTO> getAuditList(String alarmId) {
|
|
|
- List<AlarmAudit> audits = alarmAuditMapper.selectList(new LambdaQueryWrapper<AlarmAudit>()
|
|
|
- .eq(AlarmAudit::getAlarmId, alarmId)
|
|
|
- .orderByDesc(AlarmAudit::getAuditTime));
|
|
|
- return audits.stream().map(this::toAuditOutDTO).collect(Collectors.toList());
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public AlarmFlowOutDTO getAlarmFlow(String alarmId) {
|
|
|
- AlarmFlowOutDTO flow = new AlarmFlowOutDTO();
|
|
|
- flow.setAlarm(getAlarmDetail(alarmId));
|
|
|
- flow.setAuditList(getAuditList(alarmId));
|
|
|
- AlarmData alarm = alarmDataService.getById(alarmId);
|
|
|
- WorkOrder order = alarm == null || alarm.getOrderId() == null
|
|
|
- ? null : workOrderMapper.selectById(alarm.getOrderId());
|
|
|
- // 出参统一用 WorkOrderVO,实体保持纯表映射
|
|
|
- flow.setWorkOrder(WorkOrderVO.from(order));
|
|
|
- if (order != null) {
|
|
|
- EquipmentBase device = order.getDeviceId() == null ? null
|
|
|
- : equipmentBaseMapper.selectById(order.getDeviceId());
|
|
|
- flow.getWorkOrder().setDeviceCode(device == null ? null : device.getEquipmentCode());
|
|
|
- List<WorkOrderLog> logs = workOrderLogMapper.selectList(new LambdaQueryWrapper<WorkOrderLog>()
|
|
|
- .eq(WorkOrderLog::getOrderId, order.getOrderId())
|
|
|
- .orderByAsc(WorkOrderLog::getOperTime));
|
|
|
- flow.setWorkOrderLogList(toLogVOList(logs));
|
|
|
- }
|
|
|
- return flow;
|
|
|
- }
|
|
|
-
|
|
|
- private AlarmAuditOutDTO toAuditOutDTO(AlarmAudit audit) {
|
|
|
- AlarmAuditOutDTO vo = BeanUtil.copyProperties(audit, AlarmAuditOutDTO.class);
|
|
|
- vo.setAuditActionText(audit.getAuditAction() != null && audit.getAuditAction() == 2 ? "解除" : "审核");
|
|
|
- vo.setAuditResultText(audit.getAuditResult() != null && audit.getAuditResult() == 2 ? "误报" : "属实");
|
|
|
- return vo;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 操作日志实体转出参:展示字段(操作类型描述、附件列表)回填到出参,实体保持纯表映射
|
|
|
- */
|
|
|
- private List<WorkOrderLogVO> toLogVOList(List<WorkOrderLog> logs) {
|
|
|
- if (CollUtil.isEmpty(logs)) {
|
|
|
- return new ArrayList<>();
|
|
|
- }
|
|
|
- List<WorkOrderLogVO> result = new ArrayList<>(logs.size());
|
|
|
- for (WorkOrderLog log : logs) {
|
|
|
- WorkOrderLogVO vo = WorkOrderLogVO.from(log);
|
|
|
- vo.setOperTypeDesc(WorkOrderLogOperTypeEnum.getDescByCode(log.getOperType()));
|
|
|
- vo.setAttachList(splitAttach(log.getAttachUrl()));
|
|
|
- result.add(vo);
|
|
|
- }
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 操作附件 URL 拆分为列表,空串与空白项丢弃
|
|
|
- */
|
|
|
- private List<String> splitAttach(String attachUrl) {
|
|
|
- if (StrUtil.isBlank(attachUrl)) {
|
|
|
- return new ArrayList<>();
|
|
|
- }
|
|
|
- return StrUtil.split(attachUrl, ',').stream()
|
|
|
- .map(String::trim)
|
|
|
- .filter(StrUtil::isNotEmpty)
|
|
|
- .collect(Collectors.toList());
|
|
|
+ AlarmLevelEnum level = AlarmLevelEnum.fromCode(alarmLevel);
|
|
|
+ return level == null ? "未知等级" : level.getLabel();
|
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
@@ -1038,24 +608,5 @@ public class WaterSupplyAlarmServiceImpl implements IWaterSupplyAlarmService {
|
|
|
// 当前用户
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
- private Long currentUserId() {
|
|
|
- LoginUser loginUser = SecurityUtils.getLoginUser();
|
|
|
- return loginUser != null ? loginUser.getUserId() : null;
|
|
|
- }
|
|
|
|
|
|
- private Long currentDeptId() {
|
|
|
- LoginUser loginUser = SecurityUtils.getLoginUser();
|
|
|
- return loginUser != null ? loginUser.getDeptId() : null;
|
|
|
- }
|
|
|
-
|
|
|
- private String currentUserName() {
|
|
|
- LoginUser loginUser = SecurityUtils.getLoginUser();
|
|
|
- if (loginUser == null) {
|
|
|
- return "系统";
|
|
|
- }
|
|
|
- if (loginUser.getUser() != null && StrUtil.isNotBlank(loginUser.getUser().getNickName())) {
|
|
|
- return loginUser.getUser().getNickName();
|
|
|
- }
|
|
|
- return loginUser.getUsername();
|
|
|
- }
|
|
|
}
|