高级算法模块暂降综合评估
This commit is contained in:
@@ -17,4 +17,29 @@
|
|||||||
<maven.compiler.target>8</maven.compiler.target>
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.njcn</groupId>
|
||||||
|
<artifactId>common-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.njcn</groupId>
|
||||||
|
<artifactId>common-db</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.njcn</groupId>
|
||||||
|
<artifactId>common-microservice</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jna</groupId>
|
||||||
|
<artifactId>jna</artifactId>
|
||||||
|
<version>3.0.9</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.njcn.advance.pojo.bo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/20
|
||||||
|
*/
|
||||||
|
public interface FinalData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂降事件按开始时间归集门槛10秒
|
||||||
|
*/
|
||||||
|
int TIME_THRESHOLD = 10;
|
||||||
|
//分组的最大组数
|
||||||
|
int MAX_GROUP_NUM = 1000;
|
||||||
|
//类别数
|
||||||
|
int MAX_CATA_NUM = 7;
|
||||||
|
//最大事件个数
|
||||||
|
int MAX_EVT_NUM = 1000;
|
||||||
|
//三相故障
|
||||||
|
int QVVR_TYPE_THREE = 9;
|
||||||
|
//故障类型未知
|
||||||
|
int QVVR_TYPE_UNKNOWN = 10;
|
||||||
|
//节点不在网络拓扑中
|
||||||
|
int QVVR_TYPE_OUTOFRANGE = -1;
|
||||||
|
int DATA_INF = -1;
|
||||||
|
int EVT_TYPE_NUM = 6;//故障类型数
|
||||||
|
int MAX_PATH_NUM = 50;//最大路径数
|
||||||
|
int NODE_NUM = -1;//输入节点数
|
||||||
|
|
||||||
|
// 暂降综合评估算法
|
||||||
|
int CLUSER_NUM = 4; // 系统中各监测点分类后的代表节点
|
||||||
|
int MAX_LINE_NUM = 1000; // 监测点最多个数
|
||||||
|
int MAX_STA_NUM = 120; // 支持的子系统个数
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.njcn.advance.pojo.bo;
|
||||||
|
|
||||||
|
import com.njcn.advance.pojo.dto.QtIdx;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/20
|
||||||
|
*/
|
||||||
|
public class QtIdxArray extends Structure {
|
||||||
|
|
||||||
|
public QtIdx[] qtIdxs = new QtIdx[FinalData.MAX_LINE_NUM];
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List getFieldOrder() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByReference extends QtIdxArray implements Structure.ByReference {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByValue extends QtIdxArray implements Structure.ByValue {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.njcn.advance.pojo.bo;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/20
|
||||||
|
*/
|
||||||
|
public class QvvrDataStruct extends Structure {
|
||||||
|
|
||||||
|
public int sys_num; // 评估系统数目
|
||||||
|
public QtIdxArray[] line_idx = new QtIdxArray[FinalData.MAX_STA_NUM];// 评估使用,各个系统的各监测点数据
|
||||||
|
public int[] line_num = new int[FinalData.MAX_STA_NUM]; // 单个系统内的监测点数目
|
||||||
|
// 输出
|
||||||
|
public ZtpgSin[] sys_res = new ZtpgSin[FinalData.MAX_STA_NUM]; // 评估结果
|
||||||
|
|
||||||
|
public static class ByReference extends QvvrDataStruct implements Structure.ByReference {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByValue extends QvvrDataStruct implements Structure.ByValue {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getFieldOrder() { // 返回值填入的顺序
|
||||||
|
return Arrays.asList(new String[]{"sys_res"});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.njcn.advance.pojo.bo;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/20
|
||||||
|
*/
|
||||||
|
public class ZtpgSin extends Structure {
|
||||||
|
|
||||||
|
public int[] Site_rep = new int[FinalData.CLUSER_NUM]; // 系统中各个监测点分类后的代表节点
|
||||||
|
public int line_num; // 监测点数
|
||||||
|
public float[] CIV = new float[FinalData.MAX_LINE_NUM]; // 最终计算的每个监测点的相对指标得分
|
||||||
|
public int[] L = new int[FinalData.MAX_LINE_NUM]; // 每个监测点得分后的分级
|
||||||
|
public float CI; // 系统的最终评估分
|
||||||
|
|
||||||
|
public static class ByReference extends ZtpgSin implements Structure.ByReference {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByValue extends ZtpgSin implements Structure.ByValue {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList(new String[] { "Site_rep", "line_num", "CIV", "L", "CI" });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.njcn.advance.pojo.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/20
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AdvanceBaseDTO {
|
||||||
|
|
||||||
|
private String lineId;
|
||||||
|
|
||||||
|
private Float valueA;
|
||||||
|
|
||||||
|
private Integer valueB;
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.njcn.advance.pojo.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class BalanceInfo {
|
||||||
|
private String pointId;
|
||||||
|
private String pointName;
|
||||||
|
private QtIdx qtIdx;
|
||||||
|
private float civ; // 结果
|
||||||
|
private int l; // 分级
|
||||||
|
|
||||||
|
private String areaIndex; // 区域的index
|
||||||
|
private String areaName;// 区域名称
|
||||||
|
private float ci; // 系统最终的评估分
|
||||||
|
private List<PointInfo> list; // 监测点的详细信息
|
||||||
|
private int isCount; // 标识是否经过计算,默认为0-未计算,1-计算
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class PointInfo {
|
||||||
|
private String pointId;
|
||||||
|
private String pointName;
|
||||||
|
private QtIdx qtIdx;
|
||||||
|
private float civ; // 结果
|
||||||
|
private int l; // 分级
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.njcn.advance.pojo.dto;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/19
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
public class QtIdx extends Structure{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂降幅值
|
||||||
|
*/
|
||||||
|
public float r_esm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sarifi-90
|
||||||
|
*/
|
||||||
|
public int sarfi_90;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sarifi-50
|
||||||
|
*/
|
||||||
|
public int sarifi_50;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂降能量
|
||||||
|
*/
|
||||||
|
public float r_asei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 严重程度
|
||||||
|
*/
|
||||||
|
public float r_assi;
|
||||||
|
|
||||||
|
public static class ByReference extends QtIdx implements Structure.ByReference {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByValue extends QtIdx implements Structure.ByValue {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List getFieldOrder() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.njcn.advance.pojo.param;
|
||||||
|
|
||||||
|
import com.njcn.web.pojo.annotation.DateTimeStrValid;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AdvanceBaseParam {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "开始时间")
|
||||||
|
@DateTimeStrValid(message = "开始时间格式出错")
|
||||||
|
@NotBlank(message = "开始时间不可为空")
|
||||||
|
private String startTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "结束时间")
|
||||||
|
@DateTimeStrValid(message = "结束时间格式出错")
|
||||||
|
@NotBlank(message = "结束时间不可为空")
|
||||||
|
private String endTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "部门索引")
|
||||||
|
@NotBlank(message = "部门索引不可为空")
|
||||||
|
private String deptId;
|
||||||
|
}
|
||||||
@@ -23,11 +23,7 @@
|
|||||||
<artifactId>system-api</artifactId>
|
<artifactId>system-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.njcn</groupId>
|
|
||||||
<artifactId>common-oss</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.njcn</groupId>
|
<groupId>com.njcn</groupId>
|
||||||
<artifactId>user-api</artifactId>
|
<artifactId>user-api</artifactId>
|
||||||
@@ -49,18 +45,28 @@
|
|||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.squareup.okio</groupId>
|
|
||||||
<artifactId>okio</artifactId>
|
|
||||||
<version>2.8.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.njcn</groupId>
|
<groupId>com.njcn</groupId>
|
||||||
<artifactId>common-oss</artifactId>
|
<artifactId>advance-api</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.njcn</groupId>
|
||||||
|
<artifactId>event-api</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 使用JNA调用C Lib库 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jna</groupId>
|
||||||
|
<artifactId>jna</artifactId>
|
||||||
|
<version>3.0.9</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
|
|||||||
@MapperScan("com.njcn.**.mapper")
|
@MapperScan("com.njcn.**.mapper")
|
||||||
@EnableFeignClients(basePackages = "com.njcn")
|
@EnableFeignClients(basePackages = "com.njcn")
|
||||||
@SpringBootApplication(scanBasePackages = "com.njcn")
|
@SpringBootApplication(scanBasePackages = "com.njcn")
|
||||||
public class AdvanceBootMain {
|
public class AdvanceBootApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(AdvanceBootMain.class, args);
|
SpringApplication.run(AdvanceBootApplication.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.njcn.advance.controller;
|
||||||
|
|
||||||
|
import com.njcn.advance.pojo.dto.BalanceInfo;
|
||||||
|
import com.njcn.advance.pojo.param.AdvanceBaseParam;
|
||||||
|
import com.njcn.advance.service.BalanceService;
|
||||||
|
import com.njcn.common.pojo.annotation.OperateInfo;
|
||||||
|
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.HttpResultUtil;
|
||||||
|
import com.njcn.common.utils.PubUtils;
|
||||||
|
import com.njcn.web.controller.BaseController;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/19
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("balance")
|
||||||
|
@Api(tags = "暂降区域评估高级算法")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class BalanceController extends BaseController {
|
||||||
|
|
||||||
|
private final BalanceService balanceService;
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("getBalanceInfo")
|
||||||
|
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||||
|
@ApiOperation("暂降区域评估")
|
||||||
|
@ApiImplicitParam(name = "advanceBaseParam", value = "查询参数", required = true)
|
||||||
|
public HttpResult<List<BalanceInfo>> getBalanceInfo(@RequestBody @Validated AdvanceBaseParam advanceBaseParam){
|
||||||
|
String methodDescribe = getMethodDescribe("getBalanceInfo");
|
||||||
|
List<BalanceInfo> balanceInfoList = balanceService.getBalanceInfo(advanceBaseParam);
|
||||||
|
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, balanceInfoList, methodDescribe);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.njcn.advance.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.njcn.advance.pojo.dto.AdvanceBaseDTO;
|
||||||
|
import com.njcn.event.pojo.po.RmpEventDetailPO;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/19
|
||||||
|
*/
|
||||||
|
public interface BalanceMapper extends BaseMapper<RmpEventDetailPO> {
|
||||||
|
|
||||||
|
|
||||||
|
List<AdvanceBaseDTO> getFeatureAmplitude(@Param("startTime")LocalDateTime startTime, @Param("endTime")LocalDateTime endTime, @Param("lineIds")List<String> lineIds);
|
||||||
|
|
||||||
|
List<AdvanceBaseDTO> getSarfi(@Param("startTime")LocalDateTime startTime,@Param("endTime")LocalDateTime endTime,@Param("lineIds")List<String> lineIds,@Param("featureAmplitude")Float featureAmplitude);
|
||||||
|
|
||||||
|
List<AdvanceBaseDTO> getSarfiSeverity(@Param("startTime")LocalDateTime startTime,@Param("endTime")LocalDateTime endTime,@Param("lineIds")List<String> lineIds,@Param("featureAmplitude")Float featureAmplitude);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?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.advance.mapper.BalanceMapper">
|
||||||
|
|
||||||
|
<select id="getFeatureAmplitude" resultType="AdvanceBaseDTO">
|
||||||
|
select avg(feature_amplitude) valueA,measurement_point_id lineId
|
||||||
|
from r_mp_event_detail
|
||||||
|
where start_time between #{startTime} and #{endTime}
|
||||||
|
and measurement_point_id in
|
||||||
|
<foreach collection="lineIds" open="(" close=")" separator="," item="item">
|
||||||
|
#{item}
|
||||||
|
</foreach>
|
||||||
|
group by measurement_point_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
<select id="getSarfi" resultType="AdvanceBaseDTO">
|
||||||
|
select count(1) as valueB,measurement_point_id lineId
|
||||||
|
from r_mp_event_detail
|
||||||
|
where start_time between #{startTime} and #{endTime}
|
||||||
|
and measurement_point_id in
|
||||||
|
<foreach collection="lineIds" open="(" close=")" separator="," item="item">
|
||||||
|
#{item}
|
||||||
|
</foreach>
|
||||||
|
and duration < 60
|
||||||
|
and feature_amplitude < #{featureAmplitude}
|
||||||
|
group by measurement_point_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
<select id="getSarfiSeverity" resultType="AdvanceBaseDTO">
|
||||||
|
select avg(severity*duration) as valueA,measurement_point_id lineId
|
||||||
|
from r_mp_event_detail
|
||||||
|
where start_time between #{startTime} and #{endTime}
|
||||||
|
and measurement_point_id in
|
||||||
|
<foreach collection="lineIds" open="(" close=")" separator="," item="item">
|
||||||
|
#{item}
|
||||||
|
</foreach>
|
||||||
|
and duration < 60
|
||||||
|
and feature_amplitude < #{featureAmplitude}
|
||||||
|
group by measurement_point_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.njcn.advance.service;
|
||||||
|
|
||||||
|
import com.njcn.advance.pojo.dto.BalanceInfo;
|
||||||
|
import com.njcn.advance.pojo.param.AdvanceBaseParam;
|
||||||
|
import com.njcn.common.pojo.response.HttpResult;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/19
|
||||||
|
*/
|
||||||
|
public interface BalanceService {
|
||||||
|
|
||||||
|
|
||||||
|
List<BalanceInfo> getBalanceInfo(AdvanceBaseParam advanceBaseParam);
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package com.njcn.advance.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.njcn.advance.mapper.BalanceMapper;
|
||||||
|
import com.njcn.advance.pojo.dto.AdvanceBaseDTO;
|
||||||
|
import com.njcn.advance.pojo.dto.BalanceInfo;
|
||||||
|
import com.njcn.advance.pojo.dto.QtIdx;
|
||||||
|
import com.njcn.advance.pojo.param.AdvanceBaseParam;
|
||||||
|
import com.njcn.advance.service.BalanceService;
|
||||||
|
import com.njcn.advance.utils.GetBalanceUtils;
|
||||||
|
import com.njcn.common.pojo.dto.SimpleDTO;
|
||||||
|
import com.njcn.common.pojo.enums.common.ServerEnum;
|
||||||
|
import com.njcn.common.utils.PubUtils;
|
||||||
|
import com.njcn.device.pq.api.GeneralDeviceInfoClient;
|
||||||
|
import com.njcn.device.pq.pojo.dto.GeneralDeviceDTO;
|
||||||
|
import com.njcn.device.pq.pojo.param.DeviceInfoParam;
|
||||||
|
import com.njcn.event.pojo.po.RmpEventDetailPO;
|
||||||
|
import com.njcn.system.pojo.enums.StatisticsEnum;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/19
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class BalanceServiceImpl implements BalanceService {
|
||||||
|
|
||||||
|
private final GeneralDeviceInfoClient generalDeviceInfoClient;
|
||||||
|
|
||||||
|
private final BalanceMapper balanceMapper;
|
||||||
|
|
||||||
|
private final GetBalanceUtils getBalanceUtils;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BalanceInfo> getBalanceInfo(AdvanceBaseParam advanceBaseParam) {
|
||||||
|
List<BalanceInfo> balanceInfoList = new ArrayList<>();
|
||||||
|
|
||||||
|
DeviceInfoParam deviceInfoParam = new DeviceInfoParam();
|
||||||
|
deviceInfoParam.setDeptIndex(advanceBaseParam.getDeptId());
|
||||||
|
//统计类型
|
||||||
|
SimpleDTO simpleDTO = new SimpleDTO();
|
||||||
|
simpleDTO.setCode(String.valueOf(StatisticsEnum.POWER_NETWORK));
|
||||||
|
deviceInfoParam.setStatisticalType(simpleDTO);
|
||||||
|
deviceInfoParam.setServerName(ServerEnum.EVENT.getName());
|
||||||
|
List<GeneralDeviceDTO> generalDeviceDTOList = generalDeviceInfoClient.getPracticalRunDeviceInfo(deviceInfoParam).getData();
|
||||||
|
|
||||||
|
for (GeneralDeviceDTO generalDeviceDTO : generalDeviceDTOList) {
|
||||||
|
BalanceInfo balanceInfo = new BalanceInfo();
|
||||||
|
balanceInfo.setAreaIndex(generalDeviceDTO.getIndex());
|
||||||
|
balanceInfo.setAreaName(generalDeviceDTO.getName());
|
||||||
|
|
||||||
|
if (CollUtil.isEmpty(generalDeviceDTO.getLineIndexes())) {
|
||||||
|
balanceInfo.setList(new ArrayList<>());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AdvanceBaseDTO> aList = balanceMapper.getFeatureAmplitude(PubUtils.beginTimeToLocalDateTime(advanceBaseParam.getStartTime()), PubUtils.endTimeToLocalDateTime(advanceBaseParam.getEndTime()), generalDeviceDTO.getLineIndexes());
|
||||||
|
Map<String, Float> map = aList.stream().collect(Collectors.toMap(AdvanceBaseDTO::getLineId, AdvanceBaseDTO::getValueA));
|
||||||
|
|
||||||
|
List<AdvanceBaseDTO> a90List = balanceMapper.getSarfi(PubUtils.beginTimeToLocalDateTime(advanceBaseParam.getStartTime()), PubUtils.endTimeToLocalDateTime(advanceBaseParam.getEndTime()), generalDeviceDTO.getLineIndexes(), 90f);
|
||||||
|
Map<String, Integer> map90 = a90List.stream().collect(Collectors.toMap(AdvanceBaseDTO::getLineId, AdvanceBaseDTO::getValueB));
|
||||||
|
|
||||||
|
List<AdvanceBaseDTO> a50List = balanceMapper.getSarfi(PubUtils.beginTimeToLocalDateTime(advanceBaseParam.getStartTime()), PubUtils.endTimeToLocalDateTime(advanceBaseParam.getEndTime()), generalDeviceDTO.getLineIndexes(), 50f);
|
||||||
|
Map<String, Integer> map50 = a50List.stream().collect(Collectors.toMap(AdvanceBaseDTO::getLineId, AdvanceBaseDTO::getValueB));
|
||||||
|
|
||||||
|
List<AdvanceBaseDTO> aSeverityList = balanceMapper.getSarfiSeverity(PubUtils.beginTimeToLocalDateTime(advanceBaseParam.getStartTime()), PubUtils.endTimeToLocalDateTime(advanceBaseParam.getEndTime()), generalDeviceDTO.getLineIndexes(), 50f);
|
||||||
|
Map<String, Float> aSeverityListMap = aSeverityList.stream().collect(Collectors.toMap(AdvanceBaseDTO::getLineId, AdvanceBaseDTO::getValueA));
|
||||||
|
|
||||||
|
List<BalanceInfo.PointInfo> listTem = new ArrayList<>();
|
||||||
|
for (String lineId : generalDeviceDTO.getLineIndexes()) {
|
||||||
|
|
||||||
|
BalanceInfo.PointInfo pointInfo = new BalanceInfo.PointInfo();
|
||||||
|
pointInfo.setPointId(lineId);
|
||||||
|
|
||||||
|
QtIdx qtIdx = new QtIdx();
|
||||||
|
qtIdx.r_esm = MapUtils.getFloat(map,lineId,0f);
|
||||||
|
qtIdx.sarfi_90 = MapUtils.getInteger(map90,lineId,0);
|
||||||
|
qtIdx.sarifi_50 = MapUtils.getInteger(map50,lineId,0);
|
||||||
|
qtIdx.r_assi = MapUtils.getInteger(aSeverityListMap,lineId,0);
|
||||||
|
qtIdx.r_asei = MapUtils.getInteger(aSeverityListMap,lineId,0);
|
||||||
|
pointInfo.setQtIdx(qtIdx);
|
||||||
|
listTem.add(pointInfo);
|
||||||
|
}
|
||||||
|
balanceInfo.setList(listTem);
|
||||||
|
balanceInfoList.add(balanceInfo);
|
||||||
|
}
|
||||||
|
// 打包数据传入dll/so计算结果
|
||||||
|
getBalanceUtils.translateData(balanceInfoList);
|
||||||
|
return balanceInfoList;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package com.njcn.advance.utils;
|
||||||
|
|
||||||
|
import com.njcn.advance.pojo.bo.QtIdxArray;
|
||||||
|
import com.njcn.advance.pojo.bo.QvvrDataStruct;
|
||||||
|
import com.njcn.advance.pojo.dto.BalanceInfo;
|
||||||
|
import com.njcn.advance.pojo.dto.QtIdx;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/20
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class GetBalanceUtils {
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Sarifi {
|
||||||
|
private Float sarifiValue;
|
||||||
|
private Float time;
|
||||||
|
private Float pt1;
|
||||||
|
private Float pt2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void translateData(List<BalanceInfo> list) {
|
||||||
|
QvvrDataStruct qvvrDataStruct = new QvvrDataStruct();
|
||||||
|
|
||||||
|
// 过滤数据
|
||||||
|
List<BalanceInfo> newList = new ArrayList<>();
|
||||||
|
filterData(list, newList);
|
||||||
|
|
||||||
|
// 如果newList为空则不带入dll计算
|
||||||
|
if (newList.size() > 0) {
|
||||||
|
packageData(newList, qvvrDataStruct);
|
||||||
|
JnaCallDllOrSo jnaCallDll = new JnaCallBalance("qvvr_balance.dll");
|
||||||
|
jnaCallDll.setPath();
|
||||||
|
|
||||||
|
// 计算暂降综合评估
|
||||||
|
try {
|
||||||
|
JnaCallBalance.Balancelibrary INSTANTCE = JnaCallBalance.Balancelibrary.INSTANTCE;
|
||||||
|
INSTANTCE.qvvr_fun_cause(qvvrDataStruct);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultPackage(newList, qvvrDataStruct, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resultPackage(List<BalanceInfo> list, QvvrDataStruct qvvrDataStruct, List<BalanceInfo> list2) {
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
for (BalanceInfo balanceInfo : list2) {
|
||||||
|
if (balanceInfo.getAreaIndex().equals(list.get(i).getAreaIndex())) {
|
||||||
|
balanceInfo.setCi(qvvrDataStruct.sys_res[i].CI);
|
||||||
|
balanceInfo.setIsCount(1); // 已计算
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < list.get(i).getList().size(); j++) {
|
||||||
|
list.get(i).getList().get(j).setCiv(qvvrDataStruct.sys_res[i].CIV[j]); // 设置监测点的评估数据
|
||||||
|
list.get(i).getList().get(j).setL(qvvrDataStruct.sys_res[i].L[j]); // 设置监测点的评估等级
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void packageData(List<BalanceInfo> list, QvvrDataStruct qvvrDataStruct) {
|
||||||
|
qvvrDataStruct.sys_num = list.size(); // 系统数目
|
||||||
|
|
||||||
|
for (int i = 0; i < qvvrDataStruct.sys_num; i++) {
|
||||||
|
qvvrDataStruct.line_num[i] = list.get(i).getList().size(); // 监测点数目
|
||||||
|
QtIdxArray qtIdxArray = new QtIdxArray();
|
||||||
|
|
||||||
|
for (int j = 0; j < list.get(i).getList().size(); j++) {
|
||||||
|
qtIdxArray.qtIdxs[j] = list.get(i).getList().get(j).getQtIdx(); // 各监测点数据
|
||||||
|
}
|
||||||
|
|
||||||
|
qvvrDataStruct.line_idx[i] = qtIdxArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤掉没有监测点,没有暂降事件的数据
|
||||||
|
private void filterData(List<BalanceInfo> list, List<BalanceInfo> listResult) {
|
||||||
|
for (BalanceInfo balanceInfo : list) {
|
||||||
|
BalanceInfo balanceInfo2 = new BalanceInfo();
|
||||||
|
List<BalanceInfo.PointInfo> list2 = new ArrayList<>();
|
||||||
|
|
||||||
|
if (balanceInfo.getList() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < balanceInfo.getList().size(); i++) {
|
||||||
|
QtIdx qtIdx = balanceInfo.getList().get(i).getQtIdx();
|
||||||
|
|
||||||
|
if (qtIdx == null || qtIdx.sarfi_90 == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list2.add(balanceInfo.getList().get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发生事件的监测点数目少于4组不带入计算
|
||||||
|
if (list2.size() > 4) {
|
||||||
|
balanceInfo2.setAreaIndex(balanceInfo.getAreaIndex());
|
||||||
|
balanceInfo2.setList(list2);
|
||||||
|
listResult.add(balanceInfo2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BalanceInfo.PointInfo newObj(BalanceInfo.PointInfo info, double v1, int c1, int c2, double v2, double v3) {
|
||||||
|
info.getQtIdx().r_esm = (float) v1;
|
||||||
|
info.getQtIdx().sarfi_90 = c1;
|
||||||
|
info.getQtIdx().sarifi_50 = c2;
|
||||||
|
info.getQtIdx().r_asei = (float) v2;
|
||||||
|
info.getQtIdx().r_assi = (float) v3;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.njcn.advance.utils;
|
||||||
|
|
||||||
|
import com.njcn.advance.pojo.bo.QvvrDataStruct;
|
||||||
|
import com.sun.jna.Library;
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/20
|
||||||
|
*/
|
||||||
|
public class JnaCallBalance extends JnaCallDllOrSo{
|
||||||
|
|
||||||
|
public static String strpath;
|
||||||
|
|
||||||
|
public JnaCallBalance(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPath() {
|
||||||
|
JnaCallBalance.strpath = super.getStrpath();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Balancelibrary extends Library {
|
||||||
|
// 加载Lib库
|
||||||
|
Balancelibrary INSTANTCE = (Balancelibrary) Native.loadLibrary(JnaCallBalance.strpath, Balancelibrary.class);
|
||||||
|
|
||||||
|
// 定义方法--->与C方法相对应
|
||||||
|
void qvvr_fun_cause(QvvrDataStruct data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package com.njcn.advance.utils;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pqs
|
||||||
|
*
|
||||||
|
* @author cdf
|
||||||
|
* @date 2023/6/20
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class JnaCallDllOrSo {
|
||||||
|
private String path = "";
|
||||||
|
private String pathDll = "";
|
||||||
|
private String nameDll;
|
||||||
|
public static String jarPath = "";
|
||||||
|
|
||||||
|
public JnaCallDllOrSo(String name) {
|
||||||
|
super();
|
||||||
|
this.nameDll = name;
|
||||||
|
|
||||||
|
try {
|
||||||
|
String os = System.getProperty("os.name"); // 获取当前操作系统的类型
|
||||||
|
int beginIndex = os != null && os.startsWith("Windows") ? 1 : 0;// windows操作系统为1 否则为0
|
||||||
|
if(beginIndex == 0){
|
||||||
|
//linux操作系统
|
||||||
|
this.path = URLDecoder.decode(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath(), "UTF-8");
|
||||||
|
}else {
|
||||||
|
this.path = URLDecoder.decode(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath().replaceFirst("/", ""), "UTF-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
if (JnaCallDllOrSo.jarPath.equals("")) {
|
||||||
|
JnaCallDllOrSo.jarPath = this.path.substring(0, this.path.lastIndexOf('/'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String packagePath(String path) {
|
||||||
|
return path + "/" + this.nameDll;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean judgeFileType() { //判断打包方式是否为jar方式
|
||||||
|
String pathPackage = this.getClass().getPackage().toString().replaceAll("package ", "/");
|
||||||
|
pathPackage = pathPackage.replace('.', '/');
|
||||||
|
this.pathDll = packagePath(path + pathPackage);
|
||||||
|
this.pathDll = path + pathPackage + "/" + this.nameDll;
|
||||||
|
|
||||||
|
return path.endsWith(".jar");//如果dll在jar包内部返回true,否则返回true
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exitFile() {//判断dll文件是否存在
|
||||||
|
File file = new File(packagePath(JnaCallDllOrSo.jarPath));
|
||||||
|
return file.exists() || file.isFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyDll2Path() {//复制jar包中的dll到指定位置
|
||||||
|
InputStream is = this.getClass().getResourceAsStream(nameDll);
|
||||||
|
File file = new File(packagePath(JnaCallDllOrSo.jarPath));
|
||||||
|
byte[] bytes = new byte[1024];
|
||||||
|
int readBytes;
|
||||||
|
|
||||||
|
try {
|
||||||
|
OutputStream os = new FileOutputStream(file);
|
||||||
|
while ((readBytes = is.read(bytes)) != -1) {
|
||||||
|
os.write(bytes, 0, readBytes);
|
||||||
|
}
|
||||||
|
os.close();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStrpath() {
|
||||||
|
if (judgeFileType()) {
|
||||||
|
if (!exitFile()) {
|
||||||
|
copyDll2Path();
|
||||||
|
}
|
||||||
|
|
||||||
|
return packagePath(JnaCallDllOrSo.jarPath);
|
||||||
|
} else {
|
||||||
|
return this.pathDll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
pqs-advance/advance-boot/src/main/resources/libqvvr_cause_dll.so
Normal file
BIN
pqs-advance/advance-boot/src/main/resources/libqvvr_cause_dll.so
Normal file
Binary file not shown.
BIN
pqs-advance/advance-boot/src/main/resources/libqvvr_dll.so
Normal file
BIN
pqs-advance/advance-boot/src/main/resources/libqvvr_dll.so
Normal file
Binary file not shown.
BIN
pqs-advance/advance-boot/src/main/resources/libqvvr_pg_dll.so
Normal file
BIN
pqs-advance/advance-boot/src/main/resources/libqvvr_pg_dll.so
Normal file
Binary file not shown.
BIN
pqs-advance/advance-boot/src/main/resources/qvvr_balance.dll
Normal file
BIN
pqs-advance/advance-boot/src/main/resources/qvvr_balance.dll
Normal file
Binary file not shown.
BIN
pqs-advance/advance-boot/src/main/resources/qvvr_dll.dll
Normal file
BIN
pqs-advance/advance-boot/src/main/resources/qvvr_dll.dll
Normal file
Binary file not shown.
BIN
pqs-advance/advance-boot/src/main/resources/qvvr_dll_cause.dll
Normal file
BIN
pqs-advance/advance-boot/src/main/resources/qvvr_dll_cause.dll
Normal file
Binary file not shown.
@@ -70,7 +70,8 @@ public class Knife4jSwaggerConfig {
|
|||||||
"com.njcn.csdevice.controller",
|
"com.njcn.csdevice.controller",
|
||||||
"com.njcn.cswarn.controller",
|
"com.njcn.cswarn.controller",
|
||||||
"com.njcn.csharmonic.controller",
|
"com.njcn.csharmonic.controller",
|
||||||
"com.njcn.cssystem.controller"
|
"com.njcn.cssystem.controller",
|
||||||
|
"com.njcn.advance.controller"
|
||||||
)
|
)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
List<GrantType> grantTypes = new ArrayList<>();
|
List<GrantType> grantTypes = new ArrayList<>();
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
<if test="endTime != null and endTime != ''">
|
<if test="endTime != null and endTime != ''">
|
||||||
AND DATE_FORMAT(start_time, '%Y-%m-%d') <= DATE_FORMAT(#{endTime}, '%Y-%m-%d')
|
AND DATE_FORMAT(start_time, '%Y-%m-%d') <= DATE_FORMAT(#{endTime}, '%Y-%m-%d')
|
||||||
</if>
|
</if>
|
||||||
|
order by start_time desc
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 获取暂态事件明细 与上面的方法区别是日期精确到月 yy-MM -->
|
<!-- 获取暂态事件明细 与上面的方法区别是日期精确到月 yy-MM -->
|
||||||
@@ -72,4 +73,4 @@
|
|||||||
r_mp_event_detail
|
r_mp_event_detail
|
||||||
where event_id=#{id}
|
where event_id=#{id}
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
Reference in New Issue
Block a user