feat(event): 新增暂态事件列表功能

- 新增事件列表控制器,提供分页查询、详情查看和导出功能
- 实现事件列表服务和数据访问层,支持多条件查询
- 添加台账链路查询功能,关联工程、项目、设备和监测点信息
- 实现事件数据的Excel导出功能,包含完整的字段映射
- 添加相关索引优化查询性能
- 集成台账服务,支持通过台账路径筛选事件数据
This commit is contained in:
2026-05-09 13:16:56 +08:00
parent c3b074db26
commit 6f5d8dc45a
19 changed files with 1009 additions and 0 deletions

View File

@@ -58,6 +58,11 @@
<artifactId>add-ledger</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.njcn.gather</groupId>
<artifactId>event-list</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<build>

39
event/event-list/pom.xml Normal file
View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.njcn.gather</groupId>
<artifactId>event</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>event-list</artifactId>
<dependencies>
<dependency>
<groupId>com.njcn</groupId>
<artifactId>njcn-common</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>com.njcn</groupId>
<artifactId>mybatis-plus</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>com.njcn</groupId>
<artifactId>spingboot2.3.12</artifactId>
<version>2.3.12</version>
</dependency>
<dependency>
<groupId>com.njcn.gather</groupId>
<artifactId>add-ledger</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,67 @@
package com.njcn.gather.event.eventlist.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.constant.OperateType;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.LogUtil;
import com.njcn.gather.event.eventlist.pojo.param.EventListQueryParam;
import com.njcn.gather.event.eventlist.pojo.vo.EventListVO;
import com.njcn.gather.event.eventlist.service.EventListService;
import com.njcn.web.controller.BaseController;
import com.njcn.web.utils.HttpResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 事件列表接口预留入口。
*/
@Validated
@Slf4j
@Api(tags = "事件列表")
@RestController
@RequestMapping("/event/list")
@RequiredArgsConstructor
public class EventListController extends BaseController {
/** 事件列表服务。 */
private final EventListService eventListService;
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@ApiOperation("分页查询暂态事件列表")
@PostMapping("/transient/page")
public HttpResult<Page<EventListVO>> pageTransientEvents(@RequestBody EventListQueryParam param) {
String methodDescribe = getMethodDescribe("pageTransientEvents");
LogUtil.njcnDebug(log, "{}开始分页查询暂态事件列表param={}", methodDescribe, param);
Page<EventListVO> result = eventListService.pageTransientEvents(param);
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
}
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@ApiOperation("查询暂态事件详情")
@GetMapping("/transient/{eventId}")
public HttpResult<EventListVO> getTransientEventDetail(@PathVariable("eventId") String eventId) {
String methodDescribe = getMethodDescribe("getTransientEventDetail");
LogUtil.njcnDebug(log, "{}开始查询暂态事件详情eventId={}", methodDescribe, eventId);
EventListVO result = eventListService.getTransientEventDetail(eventId);
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
}
@OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.DOWNLOAD)
@ApiOperation("导出暂态事件列表")
@PostMapping("/transient/export")
public void exportTransientEvents(@RequestBody EventListQueryParam param) {
eventListService.exportTransientEvents(param);
}
}

View File

@@ -0,0 +1,21 @@
package com.njcn.gather.event.eventlist.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.gather.event.eventlist.pojo.param.EventListQueryParam;
import com.njcn.gather.event.eventlist.pojo.po.MpEventDetailPO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 暂态事件列表 Mapper。
*/
public interface EventListMapper extends BaseMapper<MpEventDetailPO> {
Page<MpEventDetailPO> selectTransientPage(Page<MpEventDetailPO> page, @Param("param") EventListQueryParam param);
List<MpEventDetailPO> selectTransientExportList(@Param("param") EventListQueryParam param, @Param("limit") Integer limit);
MpEventDetailPO selectTransientDetail(@Param("eventId") String eventId);
}

View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.njcn.gather.event.eventlist.mapper.EventListMapper">
<sql id="EventDetailColumns">
event_id,
measurement_point_id,
start_time,
event_type,
advance_reason,
advance_type,
feature_amplitude,
duration,
eventass_index,
dq_time,
deal_time,
num,
file_flag,
deal_flag,
first_time,
first_type,
first_ms,
energy,
severity,
sagsource,
phase,
event_describe,
wave_path,
create_time,
transient_value,
verify_reason,
verify_reason_detail
</sql>
<sql id="TransientWhere">
<where>
<if test="param.startTimeStart != null and param.startTimeStart != ''">
AND start_time &gt;= #{param.startTimeStart}
</if>
<if test="param.startTimeEnd != null and param.startTimeEnd != ''">
AND start_time &lt;= #{param.startTimeEnd}
</if>
<if test="param.eventType != null and param.eventType != ''">
AND event_type = #{param.eventType}
</if>
<if test="param.phase != null and param.phase != ''">
AND phase = #{param.phase}
</if>
<if test="param.eventDescribe != null and param.eventDescribe != ''">
AND event_describe LIKE CONCAT('%', #{param.eventDescribe}, '%')
</if>
<if test="param.durationMin != null">
AND duration &gt;= #{param.durationMin}
</if>
<if test="param.durationMax != null">
AND duration &lt;= #{param.durationMax}
</if>
<if test="param.featureAmplitudeMin != null">
AND feature_amplitude &gt;= #{param.featureAmplitudeMin}
</if>
<if test="param.featureAmplitudeMax != null">
AND feature_amplitude &lt;= #{param.featureAmplitudeMax}
</if>
<if test="param.fileFlag != null">
AND file_flag = #{param.fileFlag}
</if>
<if test="param.dealFlag != null">
AND deal_flag = #{param.dealFlag}
</if>
<if test="param.lineIds != null and param.lineIds.size() &gt; 0">
AND measurement_point_id IN
<foreach collection="param.lineIds" item="lineId" open="(" separator="," close=")">
#{lineId}
</foreach>
</if>
</where>
</sql>
<select id="selectTransientPage" resultType="com.njcn.gather.event.eventlist.pojo.po.MpEventDetailPO">
SELECT
<include refid="EventDetailColumns"/>
FROM r_mp_event_detail
<include refid="TransientWhere"/>
ORDER BY start_time DESC, event_id DESC
</select>
<select id="selectTransientExportList" resultType="com.njcn.gather.event.eventlist.pojo.po.MpEventDetailPO">
SELECT
<include refid="EventDetailColumns"/>
FROM r_mp_event_detail
<include refid="TransientWhere"/>
ORDER BY start_time DESC, event_id DESC
LIMIT #{limit}
</select>
<select id="selectTransientDetail" resultType="com.njcn.gather.event.eventlist.pojo.po.MpEventDetailPO">
SELECT
<include refid="EventDetailColumns"/>
FROM r_mp_event_detail
WHERE event_id = #{eventId}
LIMIT 1
</select>
</mapper>

View File

@@ -0,0 +1,68 @@
package com.njcn.gather.event.eventlist.pojo.param;
import com.njcn.web.pojo.param.BaseParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* 暂态事件列表查询参数。
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel("暂态事件列表查询参数")
public class EventListQueryParam extends BaseParam {
@ApiModelProperty("发生时刻开始,格式 yyyy-MM-dd HH:mm:ss")
private String startTimeStart;
@ApiModelProperty("发生时刻结束,格式 yyyy-MM-dd HH:mm:ss")
private String startTimeEnd;
@ApiModelProperty("事件类型")
private String eventType;
@ApiModelProperty("相别")
private String phase;
@ApiModelProperty("事件描述关键字")
private String eventDescribe;
@ApiModelProperty("持续时间下限,单位秒")
private BigDecimal durationMin;
@ApiModelProperty("持续时间上限,单位秒")
private BigDecimal durationMax;
@ApiModelProperty("暂降/暂升幅值下限")
private BigDecimal featureAmplitudeMin;
@ApiModelProperty("暂降/暂升幅值上限")
private BigDecimal featureAmplitudeMax;
@ApiModelProperty("波形文件状态0 未招1 已招")
private Integer fileFlag;
@ApiModelProperty("处理状态0 未处理1 已处理2 已处理无结果3 计算失败")
private Integer dealFlag;
@ApiModelProperty("监测点 ID 列表")
private List<String> lineIds = new ArrayList<String>();
@ApiModelProperty("工程名称关键字")
private String engineeringName;
@ApiModelProperty("项目名称关键字")
private String projectName;
@ApiModelProperty("设备名称关键字")
private String equipmentName;
@ApiModelProperty("监测点名称关键字")
private String lineName;
}

View File

@@ -0,0 +1,91 @@
package com.njcn.gather.event.eventlist.pojo.po;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 暂态事件明细。
*/
@Data
@TableName("r_mp_event_detail")
public class MpEventDetailPO implements Serializable {
private static final long serialVersionUID = 1L;
@TableId("event_id")
private String eventId;
private String measurementPointId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime startTime;
private String eventType;
private String advanceReason;
private String advanceType;
private BigDecimal featureAmplitude;
private BigDecimal duration;
private String eventassIndex;
private Double dqTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime dealTime;
private Integer num;
private Integer fileFlag;
private Integer dealFlag;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime firstTime;
private String firstType;
private BigDecimal firstMs;
private Double energy;
private Double severity;
private String sagsource;
private String phase;
private String eventDescribe;
private String wavePath;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime createTime;
private Double transientValue;
private String verifyReason;
private String verifyReasonDetail;
}

View File

@@ -0,0 +1,72 @@
package com.njcn.gather.event.eventlist.pojo.vo;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 暂态事件列表展示对象。
*/
@Data
public class EventListVO implements Serializable {
private static final long serialVersionUID = 1L;
private String eventId;
private String measurementPointId;
private String eventType;
@Excel(name = "设备名称", width = 25)
private String equipmentName;
@Excel(name = "工程名称", width = 25)
private String engineeringName;
@Excel(name = "项目名称", width = 25)
private String projectName;
@Excel(name = "发生时刻", width = 25, exportFormat = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime startTime;
@Excel(name = "监测点名称", width = 25)
private String lineName;
@Excel(name = "事件描述", width = 25)
private String eventDescribe;
@Excel(name = "事件发生位置", width = 18)
private String sagsource;
@Excel(name = "相别", width = 15)
private String phase;
@Excel(name = "持续时间(s)", width = 18)
private BigDecimal duration;
@Excel(name = "暂降/暂升幅值(%)", width = 20)
private BigDecimal featureAmplitude;
private String wavePath;
private Integer fileFlag;
private Integer dealFlag;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,17 @@
package com.njcn.gather.event.eventlist.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.gather.event.eventlist.pojo.param.EventListQueryParam;
import com.njcn.gather.event.eventlist.pojo.vo.EventListVO;
/**
* 事件列表服务。
*/
public interface EventListService {
Page<EventListVO> pageTransientEvents(EventListQueryParam param);
EventListVO getTransientEventDetail(String eventId);
void exportTransientEvents(EventListQueryParam param);
}

View File

@@ -0,0 +1,286 @@
package com.njcn.gather.event.eventlist.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.gather.event.eventlist.mapper.EventListMapper;
import com.njcn.gather.event.eventlist.pojo.param.EventListQueryParam;
import com.njcn.gather.event.eventlist.pojo.po.MpEventDetailPO;
import com.njcn.gather.event.eventlist.pojo.vo.EventListVO;
import com.njcn.gather.event.eventlist.service.EventListService;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLinePathQueryParam;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
import com.njcn.gather.tool.addledger.service.AddLedgerService;
import com.njcn.web.factory.PageFactory;
import com.njcn.web.utils.ExcelUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* 事件列表服务实现。
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class EventListServiceImpl implements EventListService {
private static final int LEDGER_LINE_QUERY_LIMIT = 1000;
private static final int EVENT_LINE_ID_QUERY_LIMIT = 1000;
private static final int EXPORT_LIMIT = 5000;
private static final String EMPTY_TEXT = "-";
private static final DateTimeFormatter OUTPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static final DateTimeFormatter[] INPUT_FORMATTERS = new DateTimeFormatter[]{
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"),
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"),
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
};
private final EventListMapper eventListMapper;
private final AddLedgerService addLedgerService;
@Override
public Page<EventListVO> pageTransientEvents(EventListQueryParam param) {
EventListQueryParam queryParam = normalizeQueryParam(param);
if (!resolveLineFilter(queryParam)) {
return emptyPage(queryParam);
}
Page<MpEventDetailPO> eventPage = eventListMapper.selectTransientPage(
new Page<MpEventDetailPO>(PageFactory.getPageNum(queryParam), PageFactory.getPageSize(queryParam)),
queryParam);
List<EventListVO> records = buildEventList(eventPage.getRecords());
Page<EventListVO> resultPage = new Page<EventListVO>(eventPage.getCurrent(), eventPage.getSize(), eventPage.getTotal());
resultPage.setRecords(records);
return resultPage;
}
@Override
public EventListVO getTransientEventDetail(String eventId) {
String normalizedEventId = trimToNull(eventId);
if (normalizedEventId == null) {
throw new BusinessException(CommonResponseEnum.FAIL, "事件 ID 不能为空");
}
MpEventDetailPO eventDetail = eventListMapper.selectTransientDetail(normalizedEventId);
if (eventDetail == null) {
throw new BusinessException(CommonResponseEnum.FAIL, "暂态事件不存在");
}
List<MpEventDetailPO> eventDetails = new ArrayList<MpEventDetailPO>();
eventDetails.add(eventDetail);
return buildEventList(eventDetails).get(0);
}
@Override
public void exportTransientEvents(EventListQueryParam param) {
EventListQueryParam queryParam = normalizeQueryParam(param);
List<EventListVO> exportRecords;
if (resolveLineFilter(queryParam)) {
List<MpEventDetailPO> eventDetails = eventListMapper.selectTransientExportList(queryParam, EXPORT_LIMIT + 1);
if (eventDetails.size() > EXPORT_LIMIT) {
throw new BusinessException(CommonResponseEnum.FAIL, "导出数据超过 5000 条,请缩小查询条件");
}
exportRecords = buildEventList(eventDetails);
} else {
exportRecords = Collections.emptyList();
}
ExcelUtil.exportExcel("暂态事件列表.xlsx", "暂态事件列表", EventListVO.class, exportRecords);
}
private List<EventListVO> buildEventList(List<MpEventDetailPO> eventDetails) {
if (eventDetails == null || eventDetails.isEmpty()) {
return Collections.emptyList();
}
List<String> lineIds = new ArrayList<String>();
for (MpEventDetailPO eventDetail : eventDetails) {
String lineId = trimToNull(eventDetail.getMeasurementPointId());
if (lineId != null && !lineIds.contains(lineId)) {
lineIds.add(lineId);
}
}
Map<String, AddLedgerLinePathVO> linePathMap = addLedgerService.listLinePathByLineIds(lineIds);
List<EventListVO> result = new ArrayList<EventListVO>();
for (MpEventDetailPO eventDetail : eventDetails) {
AddLedgerLinePathVO linePath = linePathMap.get(eventDetail.getMeasurementPointId());
result.add(buildEventVO(eventDetail, linePath));
}
return result;
}
private EventListVO buildEventVO(MpEventDetailPO eventDetail, AddLedgerLinePathVO linePath) {
EventListVO vo = new EventListVO();
vo.setEventId(eventDetail.getEventId());
vo.setMeasurementPointId(eventDetail.getMeasurementPointId());
vo.setEventType(eventDetail.getEventType());
vo.setEquipmentName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getEquipmentName()));
vo.setEngineeringName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getEngineeringName()));
vo.setProjectName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getProjectName()));
vo.setStartTime(eventDetail.getStartTime());
vo.setLineName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getLineName()));
vo.setEventDescribe(defaultText(eventDetail.getEventDescribe(), eventDetail.getEventType()));
vo.setSagsource(defaultText(eventDetail.getSagsource()));
vo.setPhase(defaultText(eventDetail.getPhase()));
vo.setDuration(eventDetail.getDuration());
vo.setFeatureAmplitude(eventDetail.getFeatureAmplitude());
vo.setWavePath(eventDetail.getWavePath());
vo.setFileFlag(eventDetail.getFileFlag());
vo.setDealFlag(eventDetail.getDealFlag());
vo.setCreateTime(eventDetail.getCreateTime());
return vo;
}
private EventListQueryParam normalizeQueryParam(EventListQueryParam param) {
EventListQueryParam queryParam = param == null ? new EventListQueryParam() : param;
LocalDateTime startTime = parseDateTime(queryParam.getStartTimeStart());
LocalDateTime endTime = parseDateTime(queryParam.getStartTimeEnd());
if (startTime == null) {
LocalDateTime now = LocalDateTime.now();
startTime = LocalDateTime.of(now.getYear(), now.getMonth(), 1, 0, 0, 0);
}
if (endTime == null) {
endTime = LocalDateTime.now();
}
if (startTime.isAfter(endTime)) {
throw new BusinessException(CommonResponseEnum.FAIL, "开始时间不能大于结束时间");
}
validateRange(queryParam.getDurationMin(), queryParam.getDurationMax(), "持续时间下限不能大于上限");
validateRange(queryParam.getFeatureAmplitudeMin(), queryParam.getFeatureAmplitudeMax(), "幅值下限不能大于上限");
validateFlag(queryParam.getFileFlag(), "波形文件状态只能是 0 或 1");
validateDealFlag(queryParam.getDealFlag());
queryParam.setStartTimeStart(OUTPUT_FORMATTER.format(startTime));
queryParam.setStartTimeEnd(OUTPUT_FORMATTER.format(endTime));
queryParam.setEventType(trimToNull(queryParam.getEventType()));
queryParam.setPhase(trimToNull(queryParam.getPhase()));
queryParam.setEventDescribe(trimToNull(queryParam.getEventDescribe()));
queryParam.setEngineeringName(trimToNull(queryParam.getEngineeringName()));
queryParam.setProjectName(trimToNull(queryParam.getProjectName()));
queryParam.setEquipmentName(trimToNull(queryParam.getEquipmentName()));
queryParam.setLineName(trimToNull(queryParam.getLineName()));
List<String> lineIds = normalizeIds(queryParam.getLineIds());
if (lineIds.size() > EVENT_LINE_ID_QUERY_LIMIT) {
throw new BusinessException(CommonResponseEnum.FAIL, "监测点 ID 查询数量不能超过 1000 个");
}
queryParam.setLineIds(lineIds);
return queryParam;
}
/**
* 台账关键字先转成测点 ID避免在事件模块直接联查台账表。
*/
private boolean resolveLineFilter(EventListQueryParam queryParam) {
if (!hasLedgerKeyword(queryParam)) {
return true;
}
AddLedgerLinePathQueryParam linePathQueryParam = new AddLedgerLinePathQueryParam();
linePathQueryParam.setEngineeringName(queryParam.getEngineeringName());
linePathQueryParam.setProjectName(queryParam.getProjectName());
linePathQueryParam.setEquipmentName(queryParam.getEquipmentName());
linePathQueryParam.setLineName(queryParam.getLineName());
linePathQueryParam.setLimit(LEDGER_LINE_QUERY_LIMIT + 1);
List<String> ledgerLineIds = addLedgerService.listLineIdsByPathQuery(linePathQueryParam);
if (ledgerLineIds.size() > LEDGER_LINE_QUERY_LIMIT) {
throw new BusinessException(CommonResponseEnum.FAIL, "台账检索匹配监测点过多,请缩小查询条件");
}
if (ledgerLineIds.isEmpty()) {
return false;
}
List<String> explicitLineIds = normalizeIds(queryParam.getLineIds());
if (explicitLineIds.isEmpty()) {
queryParam.setLineIds(ledgerLineIds);
return true;
}
List<String> intersectLineIds = new ArrayList<String>();
for (String lineId : explicitLineIds) {
if (ledgerLineIds.contains(lineId)) {
intersectLineIds.add(lineId);
}
}
queryParam.setLineIds(intersectLineIds);
return !intersectLineIds.isEmpty();
}
private Page<EventListVO> emptyPage(EventListQueryParam queryParam) {
Page<EventListVO> page = new Page<EventListVO>(PageFactory.getPageNum(queryParam), PageFactory.getPageSize(queryParam), 0);
page.setRecords(Collections.<EventListVO>emptyList());
return page;
}
private LocalDateTime parseDateTime(String value) {
String text = trimToNull(value);
if (text == null) {
return null;
}
for (DateTimeFormatter formatter : INPUT_FORMATTERS) {
try {
return LocalDateTime.parse(text, formatter);
} catch (DateTimeParseException ignored) {
// 尝试下一个前端可能传入的时间格式。
}
}
throw new BusinessException(CommonResponseEnum.FAIL, "时间格式不正确,仅支持 yyyy-MM-dd HH:mm:ss");
}
private List<String> normalizeIds(List<String> ids) {
if (ids == null || ids.isEmpty()) {
return Collections.emptyList();
}
List<String> normalizedIds = new ArrayList<String>();
for (String id : ids) {
String normalizedId = trimToNull(id);
if (normalizedId != null && !normalizedIds.contains(normalizedId)) {
normalizedIds.add(normalizedId);
}
}
return normalizedIds;
}
private boolean hasLedgerKeyword(EventListQueryParam queryParam) {
return trimToNull(queryParam.getEngineeringName()) != null
|| trimToNull(queryParam.getProjectName()) != null
|| trimToNull(queryParam.getEquipmentName()) != null
|| trimToNull(queryParam.getLineName()) != null;
}
private void validateRange(BigDecimal min, BigDecimal max, String message) {
if (min != null && max != null && min.compareTo(max) > 0) {
throw new BusinessException(CommonResponseEnum.FAIL, message);
}
}
private void validateFlag(Integer flag, String message) {
if (flag != null && flag != 0 && flag != 1) {
throw new BusinessException(CommonResponseEnum.FAIL, message);
}
}
private void validateDealFlag(Integer dealFlag) {
if (dealFlag != null && (dealFlag < 0 || dealFlag > 3)) {
throw new BusinessException(CommonResponseEnum.FAIL, "处理状态只能是 0、1、2、3");
}
}
private String defaultText(String value) {
return defaultText(value, EMPTY_TEXT);
}
private String defaultText(String value, String defaultValue) {
String text = trimToNull(value);
return text == null ? defaultValue : text;
}
private String trimToNull(String value) {
if (value == null) {
return null;
}
String trimmed = value.trim();
return trimmed.isEmpty() ? null : trimmed;
}
}

View File

@@ -0,0 +1,14 @@
-- 暂态事件列表查询建议索引。
-- 本脚本不自动执行,请按数据库现状审阅后单独执行。
CREATE INDEX idx_event_start_id
ON r_mp_event_detail (start_time, event_id);
CREATE INDEX idx_event_mp_time_id
ON r_mp_event_detail (measurement_point_id, start_time, event_id);
CREATE INDEX idx_event_type_time_id
ON r_mp_event_detail (event_type, start_time, event_id);
CREATE INDEX idx_event_phase_time_id
ON r_mp_event_detail (phase, start_time, event_id);

25
event/pom.xml Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.njcn.gather</groupId>
<artifactId>CN_Tool</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>event</artifactId>
<packaging>pom</packaging>
<modules>
<module>event-list</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@@ -16,6 +16,7 @@
<module>user</module>
<module>detection</module>
<module>tools</module>
<module>event</module>
</modules>
<distributionManagement>

View File

@@ -1,7 +1,9 @@
package com.njcn.gather.tool.addledger.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLinePathQueryParam;
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerLinePO;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -17,5 +19,9 @@ public interface AddLedgerLineMapper extends BaseMapper<AddLedgerLinePO> {
@Param("lineNo") Integer lineNo,
@Param("lineId") String lineId);
List<AddLedgerLinePathVO> selectLinePathByLineIds(@Param("lineIds") List<String> lineIds);
List<AddLedgerLinePathVO> selectLinePathByQuery(@Param("param") AddLedgerLinePathQueryParam param);
int softDeleteByIds(@Param("ids") List<String> ids, @Param("updateBy") String updateBy);
}

View File

@@ -25,6 +25,62 @@
</if>
</select>
<select id="selectLinePathByLineIds" resultType="com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO">
SELECT engineering.id AS engineeringId,
engineering.name AS engineeringName,
project.id AS projectId,
project.name AS projectName,
equipment.id AS equipmentId,
equipment.name AS equipmentName,
line.line_id AS lineId,
line.name AS lineName
FROM cs_line line
INNER JOIN cs_equipment_delivery equipment ON equipment.id = line.device_id
INNER JOIN cs_project project ON project.id = equipment.associated_project
INNER JOIN cs_engineering engineering ON engineering.id = equipment.associated_engineering
WHERE line.status = 1
AND equipment.run_status &lt;&gt; 0
AND project.status = 1
AND engineering.status = 1
AND line.line_id IN
<foreach collection="lineIds" item="lineId" open="(" separator="," close=")">
#{lineId}
</foreach>
</select>
<select id="selectLinePathByQuery" resultType="com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO">
SELECT engineering.id AS engineeringId,
engineering.name AS engineeringName,
project.id AS projectId,
project.name AS projectName,
equipment.id AS equipmentId,
equipment.name AS equipmentName,
line.line_id AS lineId,
line.name AS lineName
FROM cs_line line
INNER JOIN cs_equipment_delivery equipment ON equipment.id = line.device_id
INNER JOIN cs_project project ON project.id = equipment.associated_project
INNER JOIN cs_engineering engineering ON engineering.id = equipment.associated_engineering
WHERE line.status = 1
AND equipment.run_status &lt;&gt; 0
AND project.status = 1
AND engineering.status = 1
<if test="param.engineeringName != null and param.engineeringName != ''">
AND engineering.name LIKE CONCAT('%', #{param.engineeringName}, '%')
</if>
<if test="param.projectName != null and param.projectName != ''">
AND project.name LIKE CONCAT('%', #{param.projectName}, '%')
</if>
<if test="param.equipmentName != null and param.equipmentName != ''">
AND equipment.name LIKE CONCAT('%', #{param.equipmentName}, '%')
</if>
<if test="param.lineName != null and param.lineName != ''">
AND line.name LIKE CONCAT('%', #{param.lineName}, '%')
</if>
ORDER BY engineering.name ASC, project.name ASC, equipment.name ASC, line.name ASC
LIMIT #{param.limit}
</select>
<update id="softDeleteByIds">
UPDATE cs_line
SET status = 0,

View File

@@ -0,0 +1,26 @@
package com.njcn.gather.tool.addledger.pojo.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 监测点台账链路检索参数。
*/
@Data
public class AddLedgerLinePathQueryParam {
@ApiModelProperty("工程名称关键字")
private String engineeringName;
@ApiModelProperty("项目名称关键字")
private String projectName;
@ApiModelProperty("设备名称关键字")
private String equipmentName;
@ApiModelProperty("监测点名称关键字")
private String lineName;
@ApiModelProperty("最大返回监测点数量")
private Integer limit;
}

View File

@@ -0,0 +1,30 @@
package com.njcn.gather.tool.addledger.pojo.vo;
import lombok.Data;
import java.io.Serializable;
/**
* 监测点所属台账链路。
*/
@Data
public class AddLedgerLinePathVO implements Serializable {
private static final long serialVersionUID = 1L;
private String engineeringId;
private String engineeringName;
private String projectId;
private String projectName;
private String equipmentId;
private String equipmentName;
private String lineId;
private String lineName;
}

View File

@@ -2,12 +2,15 @@ package com.njcn.gather.tool.addledger.service;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerEngineeringSaveParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerEquipmentSaveParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLinePathQueryParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLineSaveParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerProjectSaveParam;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerDetailVO;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerTreeNodeVO;
import java.util.List;
import java.util.Map;
/**
* 数据台账服务。
@@ -28,5 +31,9 @@ public interface AddLedgerService {
List<Integer> availableLineNos(String deviceId, String lineId);
Map<String, AddLedgerLinePathVO> listLinePathByLineIds(List<String> lineIds);
List<String> listLineIdsByPathQuery(AddLedgerLinePathQueryParam param);
boolean deleteNode(String id, Integer level);
}

View File

@@ -10,6 +10,7 @@ import com.njcn.gather.tool.addledger.mapper.AddLedgerProjectMapper;
import com.njcn.gather.tool.addledger.pojo.constant.AddLedgerConst;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerEngineeringSaveParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerEquipmentSaveParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLinePathQueryParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLineSaveParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerProjectSaveParam;
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerEngineeringPO;
@@ -18,6 +19,7 @@ import com.njcn.gather.tool.addledger.pojo.po.AddLedgerLedgerPO;
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerLinePO;
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerProjectPO;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerDetailVO;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerTreeNodeVO;
import com.njcn.gather.tool.addledger.service.AddLedgerService;
import com.njcn.gather.tool.addledger.util.AddLedgerIdUtil;
@@ -29,7 +31,10 @@ import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 数据台账服务实现。
@@ -38,6 +43,9 @@ import java.util.List;
@RequiredArgsConstructor
public class AddLedgerServiceImpl implements AddLedgerService {
private static final int DEFAULT_LINE_PATH_QUERY_LIMIT = 1000;
private static final int MAX_LINE_PATH_QUERY_LIMIT = 5000;
private final AddLedgerEngineeringMapper engineeringMapper;
private final AddLedgerProjectMapper projectMapper;
private final AddLedgerEquipmentMapper equipmentMapper;
@@ -220,6 +228,43 @@ public class AddLedgerServiceImpl implements AddLedgerService {
return AddLedgerLineNoUtil.resolveAvailableLineNos(usedLineNos, null);
}
@Override
public Map<String, AddLedgerLinePathVO> listLinePathByLineIds(List<String> lineIds) {
List<String> normalizedLineIds = normalizeIds(lineIds);
if (normalizedLineIds.isEmpty()) {
return Collections.emptyMap();
}
List<AddLedgerLinePathVO> linePaths = lineMapper.selectLinePathByLineIds(normalizedLineIds);
Map<String, AddLedgerLinePathVO> result = new LinkedHashMap<String, AddLedgerLinePathVO>();
for (AddLedgerLinePathVO linePath : linePaths) {
if (linePath != null && !isBlank(linePath.getLineId())) {
result.put(linePath.getLineId(), linePath);
}
}
return result;
}
@Override
public List<String> listLineIdsByPathQuery(AddLedgerLinePathQueryParam param) {
if (!hasPathKeyword(param)) {
return Collections.emptyList();
}
AddLedgerLinePathQueryParam queryParam = new AddLedgerLinePathQueryParam();
queryParam.setEngineeringName(trimToNull(param.getEngineeringName()));
queryParam.setProjectName(trimToNull(param.getProjectName()));
queryParam.setEquipmentName(trimToNull(param.getEquipmentName()));
queryParam.setLineName(trimToNull(param.getLineName()));
queryParam.setLimit(normalizeLimit(param.getLimit()));
List<AddLedgerLinePathVO> linePaths = lineMapper.selectLinePathByQuery(queryParam);
List<String> lineIds = new ArrayList<String>();
for (AddLedgerLinePathVO linePath : linePaths) {
if (linePath != null && !isBlank(linePath.getLineId())) {
lineIds.add(linePath.getLineId());
}
}
return lineIds;
}
@Override
@Transactional
public boolean deleteNode(String id, Integer level) {
@@ -487,6 +532,35 @@ public class AddLedgerServiceImpl implements AddLedgerService {
return trimToNull(value) == null;
}
private List<String> normalizeIds(List<String> ids) {
if (ids == null || ids.isEmpty()) {
return Collections.emptyList();
}
List<String> normalizedIds = new ArrayList<String>();
for (String id : ids) {
String normalizedId = trimToNull(id);
if (normalizedId != null && !normalizedIds.contains(normalizedId)) {
normalizedIds.add(normalizedId);
}
}
return normalizedIds;
}
private boolean hasPathKeyword(AddLedgerLinePathQueryParam param) {
return param != null
&& (trimToNull(param.getEngineeringName()) != null
|| trimToNull(param.getProjectName()) != null
|| trimToNull(param.getEquipmentName()) != null
|| trimToNull(param.getLineName()) != null);
}
private int normalizeLimit(Integer limit) {
if (limit == null || limit <= 0) {
return DEFAULT_LINE_PATH_QUERY_LIMIT;
}
return Math.min(limit, MAX_LINE_PATH_QUERY_LIMIT);
}
private String currentUserId() {
try {
String userId = RequestUtil.getUserId();