|
@@ -0,0 +1,543 @@
|
|
|
|
|
+package com.zksy.dispatch.service.impl;
|
|
|
|
|
+
|
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
|
|
+import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
+import com.zksy.common.exception.ServiceException;
|
|
|
|
|
+import com.zksy.common.utils.SecurityUtils;
|
|
|
|
|
+import com.zksy.dispatch.domain.DisEvent;
|
|
|
|
|
+import com.zksy.dispatch.domain.DisEventReport;
|
|
|
|
|
+import com.zksy.dispatch.domain.DisEventTrack;
|
|
|
|
|
+import com.zksy.dispatch.domain.DisEventTrackLog;
|
|
|
|
|
+import com.zksy.dispatch.domain.DisEventTransfer;
|
|
|
|
|
+import com.zksy.dispatch.domain.DisEventUrge;
|
|
|
|
|
+import com.zksy.dispatch.domain.DisEventVerify;
|
|
|
|
|
+import com.zksy.dispatch.dto.DisEventPageDTO;
|
|
|
|
|
+import com.zksy.dispatch.dto.DisEventVO;
|
|
|
|
|
+import com.zksy.dispatch.dto.EventStatsVO;
|
|
|
|
|
+import com.zksy.dispatch.mapper.DisEventMapper;
|
|
|
|
|
+import com.zksy.dispatch.mapper.DisEventReportMapper;
|
|
|
|
|
+import com.zksy.dispatch.mapper.DisEventTrackLogMapper;
|
|
|
|
|
+import com.zksy.dispatch.mapper.DisEventTrackMapper;
|
|
|
|
|
+import com.zksy.dispatch.mapper.DisEventTransferMapper;
|
|
|
|
|
+import com.zksy.dispatch.mapper.DisEventUrgeMapper;
|
|
|
|
|
+import com.zksy.dispatch.mapper.DisEventVerifyMapper;
|
|
|
|
|
+import com.zksy.dispatch.service.DisEventService;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
|
|
+
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
|
|
+import java.math.RoundingMode;
|
|
|
|
|
+import java.time.LocalDate;
|
|
|
|
|
+import java.time.LocalDateTime;
|
|
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
|
|
+import java.util.Collections;
|
|
|
|
|
+import java.util.HashMap;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+import java.util.Objects;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 应急事件统一档案 Service 实现(全生命周期闭环)
|
|
|
|
|
+ * 状态机:待受理 -> 待核实 -> 已核实 -> 处置中 -> 已解除 -> 已关闭;不实事件为终止态
|
|
|
|
|
+ */
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@Service
|
|
|
|
|
+public class DisEventServiceImpl extends ServiceImpl<DisEventMapper, DisEvent>
|
|
|
|
|
+ implements DisEventService {
|
|
|
|
|
+
|
|
|
|
|
+ /** 事件状态常量 */
|
|
|
|
|
+ private static final String STATUS_WAIT_ACCEPT = "待受理";
|
|
|
|
|
+ private static final String STATUS_WAIT_VERIFY = "待核实";
|
|
|
|
|
+ private static final String STATUS_VERIFIED = "已核实";
|
|
|
|
|
+ private static final String STATUS_PROCESSING = "处置中";
|
|
|
|
|
+ private static final String STATUS_RELEASED = "已解除";
|
|
|
|
|
+ private static final String STATUS_CLOSED = "已关闭";
|
|
|
|
|
+ private static final String STATUS_FALSE = "不实事件";
|
|
|
|
|
+
|
|
|
|
|
+ /** 事件编号格式:SJ+yyyyMMddHHmmss */
|
|
|
|
|
+ private static final DateTimeFormatter NO_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private DisEventReportMapper reportMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private DisEventVerifyMapper verifyMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private DisEventTransferMapper transferMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private DisEventTrackMapper trackMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private DisEventTrackLogMapper trackLogMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private DisEventUrgeMapper urgeMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private ObjectMapper objectMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public DisEvent saveReport(DisEvent event) {
|
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
+ // 自动生成全局唯一事件编号
|
|
|
|
|
+ event.setEventNo("SJ" + now.format(NO_FORMAT));
|
|
|
|
|
+ event.setStatus(STATUS_WAIT_ACCEPT);
|
|
|
|
|
+ event.setReportTime(now);
|
|
|
|
|
+ event.setCreateTime(now);
|
|
|
|
|
+ event.setCreateBy(currentUser());
|
|
|
|
|
+ save(event);
|
|
|
|
|
+ // 同步写接报明细(挂靠主表)
|
|
|
|
|
+ DisEventReport report = new DisEventReport();
|
|
|
|
|
+ report.setRelEventId(event.getId());
|
|
|
|
|
+ report.setEventNo(event.getEventNo());
|
|
|
|
|
+ report.setSource(event.getSource());
|
|
|
|
|
+ report.setLocation(event.getLocation());
|
|
|
|
|
+ report.setHappenTime(event.getHappenTime());
|
|
|
|
|
+ report.setDescription(event.getDescription());
|
|
|
|
|
+ report.setReporter(event.getReporter());
|
|
|
|
|
+ report.setReportTime(event.getReportTime());
|
|
|
|
|
+ report.setChannel(event.getChannel());
|
|
|
|
|
+ report.setStatus(STATUS_WAIT_ACCEPT);
|
|
|
|
|
+ report.setCreateTime(now);
|
|
|
|
|
+ reportMapper.insert(report);
|
|
|
|
|
+ return event;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Page<DisEventVO> findByPage(DisEventPageDTO dto) {
|
|
|
|
|
+ Page<DisEvent> page = new Page<>(dto.getPageNum(), dto.getPageSize());
|
|
|
|
|
+ LambdaQueryWrapper<DisEvent> wrapper = buildWrapper(dto);
|
|
|
|
|
+ wrapper.orderByDesc(DisEvent::getHappenTime).orderByDesc(DisEvent::getCreateTime);
|
|
|
|
|
+ page(page, wrapper);
|
|
|
|
|
+
|
|
|
|
|
+ Page<DisEventVO> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
|
|
|
|
+ List<DisEvent> records = page.getRecords();
|
|
|
|
|
+ if (CollectionUtils.isEmpty(records)) {
|
|
|
|
|
+ voPage.setRecords(Collections.emptyList());
|
|
|
|
|
+ return voPage;
|
|
|
|
|
+ }
|
|
|
|
|
+ List<Long> ids = records.stream().map(DisEvent::getId).collect(Collectors.toList());
|
|
|
|
|
+ Map<Long, DisEventTransfer> transferMap = latestTransferMap(ids);
|
|
|
|
|
+ Map<Long, DisEventTrack> trackMap = latestTrackMap(ids);
|
|
|
|
|
+ List<DisEventVO> vos = records.stream().map(e -> {
|
|
|
|
|
+ DisEventVO vo = new DisEventVO();
|
|
|
|
|
+ BeanUtils.copyProperties(e, vo);
|
|
|
|
|
+ DisEventTransfer t = transferMap.get(e.getId());
|
|
|
|
|
+ if (t != null) {
|
|
|
|
|
+ vo.setTransferDept(t.getTransferDept());
|
|
|
|
|
+ vo.setReportTargets(t.getReportTargets());
|
|
|
|
|
+ vo.setTransferTime(t.getTransferTime());
|
|
|
|
|
+ vo.setTransferId(t.getId());
|
|
|
|
|
+ }
|
|
|
|
|
+ DisEventTrack tk = trackMap.get(e.getId());
|
|
|
|
|
+ if (tk != null) {
|
|
|
|
|
+ vo.setLastVisitTime(tk.getLastVisitTime());
|
|
|
|
|
+ vo.setNextVisitTime(tk.getNextVisitTime());
|
|
|
|
|
+ vo.setTrackId(tk.getId());
|
|
|
|
|
+ }
|
|
|
|
|
+ return vo;
|
|
|
|
|
+ }).collect(Collectors.toList());
|
|
|
|
|
+ voPage.setRecords(vos);
|
|
|
|
|
+ return voPage;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public DisEventVO getDetail(Long id) {
|
|
|
|
|
+ DisEvent e = getById(id);
|
|
|
|
|
+ if (e == null) {
|
|
|
|
|
+ throw new ServiceException("事件不存在:" + id);
|
|
|
|
|
+ }
|
|
|
|
|
+ DisEventVO vo = new DisEventVO();
|
|
|
|
|
+ BeanUtils.copyProperties(e, vo);
|
|
|
|
|
+ Map<String, List<Map<String, Object>>> process = new HashMap<>();
|
|
|
|
|
+ process.put("transferList", listMap(transferMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<DisEventTransfer>()
|
|
|
|
|
+ .eq(DisEventTransfer::getRelEventId, id)
|
|
|
|
|
+ .orderByDesc(DisEventTransfer::getId))));
|
|
|
|
|
+ process.put("verifyList", listMap(verifyMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<DisEventVerify>()
|
|
|
|
|
+ .eq(DisEventVerify::getRelEventId, id)
|
|
|
|
|
+ .orderByDesc(DisEventVerify::getId))));
|
|
|
|
|
+ process.put("trackList", listMap(trackMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<DisEventTrack>()
|
|
|
|
|
+ .eq(DisEventTrack::getRelEventId, id)
|
|
|
|
|
+ .orderByDesc(DisEventTrack::getId))));
|
|
|
|
|
+ process.put("urgeList", listMap(urgeMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<DisEventUrge>()
|
|
|
|
|
+ .eq(DisEventUrge::getRelEventId, id)
|
|
|
|
|
+ .orderByDesc(DisEventUrge::getId))));
|
|
|
|
|
+ vo.setProcess(process);
|
|
|
|
|
+ return vo;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public void accept(Long id) {
|
|
|
|
|
+ DisEvent db = requireEvent(id);
|
|
|
|
|
+ if (!STATUS_WAIT_ACCEPT.equals(db.getStatus())) {
|
|
|
|
|
+ throw new ServiceException("当前状态【" + db.getStatus() + "】不可受理");
|
|
|
|
|
+ }
|
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
+ db.setStatus(STATUS_WAIT_VERIFY);
|
|
|
|
|
+ db.setUpdateTime(now);
|
|
|
|
|
+ db.setUpdateBy(currentUser());
|
|
|
|
|
+ updateById(db);
|
|
|
|
|
+ // 同步接报明细状态
|
|
|
|
|
+ DisEventReport report = reportMapper.selectOne(
|
|
|
|
|
+ new LambdaQueryWrapper<DisEventReport>()
|
|
|
|
|
+ .eq(DisEventReport::getRelEventId, id)
|
|
|
|
|
+ .orderByDesc(DisEventReport::getId)
|
|
|
|
|
+ .last("LIMIT 1"));
|
|
|
|
|
+ if (report != null) {
|
|
|
|
|
+ report.setStatus(STATUS_WAIT_VERIFY);
|
|
|
|
|
+ report.setUpdateTime(now);
|
|
|
|
|
+ reportMapper.updateById(report);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public void verify(DisEvent event) {
|
|
|
|
|
+ DisEvent db = requireEvent(event.getId());
|
|
|
|
|
+ if (!STATUS_WAIT_VERIFY.equals(db.getStatus())) {
|
|
|
|
|
+ throw new ServiceException("当前状态【" + db.getStatus() + "】不可核实");
|
|
|
|
|
+ }
|
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
+ db.setCategory(event.getCategory());
|
|
|
|
|
+ db.setLevel(event.getLevel());
|
|
|
|
|
+ db.setJudgeTime(now);
|
|
|
|
|
+ db.setVerifier(currentUser());
|
|
|
|
|
+ db.setVerifyTime(now);
|
|
|
|
|
+ db.setVerifyOpinion(event.getVerifyOpinion());
|
|
|
|
|
+ // 不实事件为终止态
|
|
|
|
|
+ db.setStatus("不实".equals(event.getIsReal()) ? STATUS_FALSE : STATUS_VERIFIED);
|
|
|
|
|
+ db.setUpdateTime(now);
|
|
|
|
|
+ db.setUpdateBy(currentUser());
|
|
|
|
|
+ updateById(db);
|
|
|
|
|
+ // 写核实明细(挂靠主表)
|
|
|
|
|
+ DisEventVerify v = new DisEventVerify();
|
|
|
|
|
+ v.setRelEventId(db.getId());
|
|
|
|
|
+ v.setReportId(null);
|
|
|
|
|
+ v.setEventNo(db.getEventNo());
|
|
|
|
|
+ v.setCategory(event.getCategory());
|
|
|
|
|
+ v.setLevel(event.getLevel());
|
|
|
|
|
+ v.setLocation(db.getLocation());
|
|
|
|
|
+ v.setDescription(db.getDescription());
|
|
|
|
|
+ v.setJudgeTime(now);
|
|
|
|
|
+ v.setVerifier(currentUser());
|
|
|
|
|
+ v.setVerifyTime(now);
|
|
|
|
|
+ v.setOpinion(event.getVerifyOpinion());
|
|
|
|
|
+ v.setIsReal(event.getIsReal());
|
|
|
|
|
+ v.setStatus(db.getStatus());
|
|
|
|
|
+ v.setCreateTime(now);
|
|
|
|
|
+ verifyMapper.insert(v);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public void transfer(DisEventTransfer transfer) {
|
|
|
|
|
+ DisEvent db = requireEvent(transfer.getRelEventId());
|
|
|
|
|
+ if (!STATUS_VERIFIED.equals(db.getStatus()) && !STATUS_PROCESSING.equals(db.getStatus())) {
|
|
|
|
|
+ throw new ServiceException("当前状态【" + db.getStatus() + "】不可转接");
|
|
|
|
|
+ }
|
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
+ // 更新主表:责任单位 + 进入处置中
|
|
|
|
|
+ db.setDepartment(transfer.getTransferDept());
|
|
|
|
|
+ db.setStatus(STATUS_PROCESSING);
|
|
|
|
|
+ db.setUpdateTime(now);
|
|
|
|
|
+ db.setUpdateBy(currentUser());
|
|
|
|
|
+ updateById(db);
|
|
|
|
|
+ // 写转接明细(挂靠主表)
|
|
|
|
|
+ DisEventTransfer t = new DisEventTransfer();
|
|
|
|
|
+ t.setRelEventId(db.getId());
|
|
|
|
|
+ t.setEventNo(db.getEventNo());
|
|
|
|
|
+ t.setCategory(db.getCategory());
|
|
|
|
|
+ t.setLevel(db.getLevel());
|
|
|
|
|
+ t.setSummary(db.getDescription());
|
|
|
|
|
+ t.setTransferDept(transfer.getTransferDept());
|
|
|
|
|
+ t.setTransferRemark(transfer.getTransferRemark());
|
|
|
|
|
+ t.setTransferTime(now);
|
|
|
|
|
+ t.setStatus("待报送");
|
|
|
|
|
+ t.setOperator(currentUser());
|
|
|
|
|
+ t.setCreateTime(now);
|
|
|
|
|
+ transferMapper.insert(t);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public void report(DisEventTransfer transfer) {
|
|
|
|
|
+ DisEventTransfer t = transferMapper.selectById(transfer.getId());
|
|
|
|
|
+ if (t == null) {
|
|
|
|
|
+ throw new ServiceException("转接记录不存在:" + transfer.getId());
|
|
|
|
|
+ }
|
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
+ t.setReportTargets(transfer.getReportTargets());
|
|
|
|
|
+ t.setAttachPaths(transfer.getAttachPaths());
|
|
|
|
|
+ if (StringUtils.isBlank(t.getReportEventNo())) {
|
|
|
|
|
+ t.setReportEventNo("BS" + now.format(NO_FORMAT));
|
|
|
|
|
+ }
|
|
|
|
|
+ t.setStatus("已报送");
|
|
|
|
|
+ t.setUpdateTime(now);
|
|
|
|
|
+ transferMapper.updateById(t);
|
|
|
|
|
+ // 事件保持处置中
|
|
|
|
|
+ if (t.getRelEventId() != null) {
|
|
|
|
|
+ DisEvent db = getById(t.getRelEventId());
|
|
|
|
|
+ if (db != null && !STATUS_PROCESSING.equals(db.getStatus())) {
|
|
|
|
|
+ db.setStatus(STATUS_PROCESSING);
|
|
|
|
|
+ db.setUpdateTime(now);
|
|
|
|
|
+ db.setUpdateBy(currentUser());
|
|
|
|
|
+ updateById(db);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public void track(DisEventTrack track) {
|
|
|
|
|
+ DisEvent db = requireEvent(track.getRelEventId());
|
|
|
|
|
+ if (!STATUS_PROCESSING.equals(db.getStatus())) {
|
|
|
|
|
+ throw new ServiceException("当前状态【" + db.getStatus() + "】不可跟踪");
|
|
|
|
|
+ }
|
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
+ // 写跟踪单(挂靠主表)
|
|
|
|
|
+ DisEventTrack tk = new DisEventTrack();
|
|
|
|
|
+ tk.setRelEventId(db.getId());
|
|
|
|
|
+ tk.setEventNo(db.getEventNo());
|
|
|
|
|
+ tk.setCategory(db.getCategory());
|
|
|
|
|
+ tk.setLevel(db.getLevel());
|
|
|
|
|
+ tk.setLocation(db.getLocation());
|
|
|
|
|
+ tk.setDescription(db.getDescription());
|
|
|
|
|
+ tk.setHandler(StringUtils.isNotBlank(track.getHandler()) ? track.getHandler() : currentUser());
|
|
|
|
|
+ tk.setStatus(STATUS_PROCESSING);
|
|
|
|
|
+ tk.setLastVisitTime(now);
|
|
|
|
|
+ tk.setNextVisitTime(track.getNextVisitTime());
|
|
|
|
|
+ tk.setCreateTime(now);
|
|
|
|
|
+ trackMapper.insert(tk);
|
|
|
|
|
+ // 写跟踪日志(时间线展示)
|
|
|
|
|
+ DisEventTrackLog logRec = new DisEventTrackLog();
|
|
|
|
|
+ logRec.setTrackId(tk.getId());
|
|
|
|
|
+ logRec.setEventNo(db.getEventNo());
|
|
|
|
|
+ logRec.setTitle("跟踪记录");
|
|
|
|
|
+ logRec.setContent(track.getDescription());
|
|
|
|
|
+ logRec.setType("primary");
|
|
|
|
|
+ logRec.setAssessment(track.getAssessment());
|
|
|
|
|
+ logRec.setNeedUpgrade(track.getNeedUpgrade());
|
|
|
|
|
+ logRec.setActionTime(now);
|
|
|
|
|
+ logRec.setCreateTime(now);
|
|
|
|
|
+ trackLogMapper.insert(logRec);
|
|
|
|
|
+ // 更新主表处置负责人与回访时间
|
|
|
|
|
+ db.setHandler(tk.getHandler());
|
|
|
|
|
+ db.setUpdateTime(now);
|
|
|
|
|
+ db.setUpdateBy(currentUser());
|
|
|
|
|
+ updateById(db);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public void release(Long id) {
|
|
|
|
|
+ DisEvent db = requireEvent(id);
|
|
|
|
|
+ if (!STATUS_PROCESSING.equals(db.getStatus())) {
|
|
|
|
|
+ throw new ServiceException("当前状态【" + db.getStatus() + "】不可解除");
|
|
|
|
|
+ }
|
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
+ db.setStatus(STATUS_RELEASED);
|
|
|
|
|
+ db.setUpdateTime(now);
|
|
|
|
|
+ db.setUpdateBy(currentUser());
|
|
|
|
|
+ updateById(db);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public void close(DisEvent event) {
|
|
|
|
|
+ DisEvent db = requireEvent(event.getId());
|
|
|
|
|
+ if (!STATUS_RELEASED.equals(db.getStatus())) {
|
|
|
|
|
+ throw new ServiceException("当前状态【" + db.getStatus() + "】不可关闭");
|
|
|
|
|
+ }
|
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
+ db.setStatus(STATUS_CLOSED);
|
|
|
|
|
+ db.setCloseReason(event.getCloseReason());
|
|
|
|
|
+ db.setCloseRemark(event.getCloseRemark());
|
|
|
|
|
+ db.setCloseTime(now);
|
|
|
|
|
+ if (event.getLossAmount() != null) {
|
|
|
|
|
+ db.setLossAmount(event.getLossAmount());
|
|
|
|
|
+ }
|
|
|
|
|
+ db.setUpdateTime(now);
|
|
|
|
|
+ db.setUpdateBy(currentUser());
|
|
|
|
|
+ updateById(db);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public EventStatsVO stats(DisEventPageDTO dto) {
|
|
|
|
|
+ List<DisEvent> events = list(buildWrapper(dto));
|
|
|
|
|
+ EventStatsVO vo = new EventStatsVO();
|
|
|
|
|
+ vo.setTotalEvents((long) events.size());
|
|
|
|
|
+ BigDecimal totalLoss = events.stream()
|
|
|
|
|
+ .map(DisEvent::getLossAmount)
|
|
|
|
|
+ .filter(Objects::nonNull)
|
|
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
+ vo.setTotalLoss(totalLoss);
|
|
|
|
|
+ long lossCount = events.stream().filter(e -> e.getLossAmount() != null).count();
|
|
|
|
|
+ vo.setAvgLoss(lossCount == 0 ? BigDecimal.ZERO
|
|
|
|
|
+ : totalLoss.divide(BigDecimal.valueOf(lossCount), 2, RoundingMode.HALF_UP));
|
|
|
|
|
+ long majorEvents = events.stream()
|
|
|
|
|
+ .filter(e -> "重大".equals(e.getLevel()) || "特别重大".equals(e.getLevel()))
|
|
|
|
|
+ .count();
|
|
|
|
|
+ vo.setMajorEvents(majorEvents);
|
|
|
|
|
+ return vo;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public void updateEvent(DisEvent event) {
|
|
|
|
|
+ DisEvent db = requireEvent(event.getId());
|
|
|
|
|
+ BeanUtils.copyProperties(event, db,
|
|
|
|
|
+ "id", "eventNo", "status", "reportTime", "createBy", "createTime", "updateTime", "delFlag");
|
|
|
|
|
+ db.setUpdateTime(LocalDateTime.now());
|
|
|
|
|
+ db.setUpdateBy(currentUser());
|
|
|
|
|
+ updateById(db);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建多维条件查询条件(列表与统计共用)
|
|
|
|
|
+ */
|
|
|
|
|
+ private LambdaQueryWrapper<DisEvent> buildWrapper(DisEventPageDTO dto) {
|
|
|
|
|
+ LambdaQueryWrapper<DisEvent> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ wrapper.like(StringUtils.isNotBlank(dto.getEventNo()), DisEvent::getEventNo, dto.getEventNo());
|
|
|
|
|
+ wrapper.like(StringUtils.isNotBlank(dto.getEventName()), DisEvent::getEventName, dto.getEventName());
|
|
|
|
|
+ wrapper.eq(StringUtils.isNotBlank(dto.getEventType()), DisEvent::getEventType, dto.getEventType());
|
|
|
|
|
+ wrapper.eq(StringUtils.isNotBlank(dto.getCategory()), DisEvent::getCategory, dto.getCategory());
|
|
|
|
|
+ wrapper.eq(StringUtils.isNotBlank(dto.getLevel()), DisEvent::getLevel, dto.getLevel());
|
|
|
|
|
+ wrapper.eq(StringUtils.isNotBlank(dto.getSource()), DisEvent::getSource, dto.getSource());
|
|
|
|
|
+ wrapper.eq(StringUtils.isNotBlank(dto.getRegion()), DisEvent::getRegion, dto.getRegion());
|
|
|
|
|
+ wrapper.eq(StringUtils.isNotBlank(dto.getDepartment()), DisEvent::getDepartment, dto.getDepartment());
|
|
|
|
|
+ if (!CollectionUtils.isEmpty(dto.getStatusList())) {
|
|
|
|
|
+ wrapper.in(DisEvent::getStatus, dto.getStatusList());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ wrapper.eq(StringUtils.isNotBlank(dto.getStatus()), DisEvent::getStatus, dto.getStatus());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (StringUtils.isNotBlank(dto.getStartDate())) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ wrapper.ge(DisEvent::getHappenTime, LocalDate.parse(dto.getStartDate()).atStartOfDay());
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("开始日期格式错误: {}", dto.getStartDate());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (StringUtils.isNotBlank(dto.getEndDate())) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ wrapper.lt(DisEvent::getHappenTime, LocalDate.parse(dto.getEndDate()).plusDays(1).atStartOfDay());
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("结束日期格式错误: {}", dto.getEndDate());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ applyLossRange(wrapper, dto.getLossRange());
|
|
|
|
|
+ return wrapper;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 损失情况区间条件
|
|
|
|
|
+ */
|
|
|
|
|
+ private void applyLossRange(LambdaQueryWrapper<DisEvent> wrapper, String lossRange) {
|
|
|
|
|
+ if (StringUtils.isBlank(lossRange)) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ switch (lossRange) {
|
|
|
|
|
+ case "100万以下":
|
|
|
|
|
+ wrapper.lt(DisEvent::getLossAmount, new BigDecimal(100));
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "100-500万":
|
|
|
|
|
+ wrapper.ge(DisEvent::getLossAmount, new BigDecimal(100))
|
|
|
|
|
+ .lt(DisEvent::getLossAmount, new BigDecimal(500));
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "500-1000万":
|
|
|
|
|
+ wrapper.ge(DisEvent::getLossAmount, new BigDecimal(500))
|
|
|
|
|
+ .lt(DisEvent::getLossAmount, new BigDecimal(1000));
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "1000万以上":
|
|
|
|
|
+ wrapper.ge(DisEvent::getLossAmount, new BigDecimal(1000));
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 查询每个事件最近一条转接记录
|
|
|
|
|
+ */
|
|
|
|
|
+ private Map<Long, DisEventTransfer> latestTransferMap(List<Long> ids) {
|
|
|
|
|
+ Map<Long, DisEventTransfer> map = new HashMap<>();
|
|
|
|
|
+ if (CollectionUtils.isEmpty(ids)) {
|
|
|
|
|
+ return map;
|
|
|
|
|
+ }
|
|
|
|
|
+ List<DisEventTransfer> list = transferMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<DisEventTransfer>()
|
|
|
|
|
+ .in(DisEventTransfer::getRelEventId, ids)
|
|
|
|
|
+ .orderByDesc(DisEventTransfer::getId));
|
|
|
|
|
+ for (DisEventTransfer t : list) {
|
|
|
|
|
+ map.putIfAbsent(t.getRelEventId(), t);
|
|
|
|
|
+ }
|
|
|
|
|
+ return map;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 查询每个事件最近一条跟踪记录
|
|
|
|
|
+ */
|
|
|
|
|
+ private Map<Long, DisEventTrack> latestTrackMap(List<Long> ids) {
|
|
|
|
|
+ Map<Long, DisEventTrack> map = new HashMap<>();
|
|
|
|
|
+ if (CollectionUtils.isEmpty(ids)) {
|
|
|
|
|
+ return map;
|
|
|
|
|
+ }
|
|
|
|
|
+ List<DisEventTrack> list = trackMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<DisEventTrack>()
|
|
|
|
|
+ .in(DisEventTrack::getRelEventId, ids)
|
|
|
|
|
+ .orderByDesc(DisEventTrack::getId));
|
|
|
|
|
+ for (DisEventTrack tk : list) {
|
|
|
|
|
+ map.putIfAbsent(tk.getRelEventId(), tk);
|
|
|
|
|
+ }
|
|
|
|
|
+ return map;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 实体列表转 Map 列表(环节明细序列化)
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<Map<String, Object>> listMap(List<?> list) {
|
|
|
|
|
+ if (CollectionUtils.isEmpty(list)) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+ return list.stream().map(item -> objectMapper.convertValue(item, new TypeReference<Map<String, Object>>() {}))
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取事件并校验存在
|
|
|
|
|
+ */
|
|
|
|
|
+ private DisEvent requireEvent(Long id) {
|
|
|
|
|
+ DisEvent db = getById(id);
|
|
|
|
|
+ if (db == null) {
|
|
|
|
|
+ throw new ServiceException("事件不存在:" + id);
|
|
|
|
|
+ }
|
|
|
|
|
+ return db;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 当前登录用户(未登录时返回系统)
|
|
|
|
|
+ */
|
|
|
|
|
+ private String currentUser() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ return SecurityUtils.getUsername();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return "system";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|