1.完成输运任务基础接口2.修改气象数据部分接口
This commit is contained in:
parent
20625bdcad
commit
f52789064d
|
|
@ -189,9 +189,6 @@ public interface CommonConstant {
|
||||||
*/
|
*/
|
||||||
String CLOUD_SERVER_KEY = "spring.cloud.nacos.discovery.server-addr";
|
String CLOUD_SERVER_KEY = "spring.cloud.nacos.discovery.server-addr";
|
||||||
|
|
||||||
/** 系统通告消息状态:1=已发布 */
|
|
||||||
String ANNOUNCEMENT_SEND_STATUS_1 = "1";
|
|
||||||
|
|
||||||
/**POST请求*/
|
/**POST请求*/
|
||||||
String HTTP_POST = "POST";
|
String HTTP_POST = "POST";
|
||||||
|
|
||||||
|
|
@ -210,9 +207,6 @@ public interface CommonConstant {
|
||||||
/**String 类型的空值*/
|
/**String 类型的空值*/
|
||||||
String STRING_NULL = "null";
|
String STRING_NULL = "null";
|
||||||
|
|
||||||
/**前端vue3版本Header参数名*/
|
|
||||||
String VERSION="X-Version";
|
|
||||||
|
|
||||||
/**存储在线程变量里的动态表名*/
|
/**存储在线程变量里的动态表名*/
|
||||||
String DYNAMIC_TABLE_NAME="DYNAMIC_TABLE_NAME";
|
String DYNAMIC_TABLE_NAME="DYNAMIC_TABLE_NAME";
|
||||||
|
|
||||||
|
|
@ -276,4 +270,8 @@ public interface CommonConstant {
|
||||||
* 缓存用户最后一次收到消息通知的时间 KEY
|
* 缓存用户最后一次收到消息通知的时间 KEY
|
||||||
*/
|
*/
|
||||||
String CACHE_KEY_USER_LAST_ANNOUNT_TIME_1HOUR = "sys:cache:userinfo:user_last_annount_time::%s";
|
String CACHE_KEY_USER_LAST_ANNOUNT_TIME_1HOUR = "sys:cache:userinfo:user_last_annount_time::%s";
|
||||||
|
|
||||||
|
String ALL_STATIONS = "stations";
|
||||||
|
|
||||||
|
String ALL_NUCLEARFACILITY = "nuclearfacility";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ package org.jeecg.common.constant.enums;
|
||||||
public enum SourceRebuildTaskStatusEnum {
|
public enum SourceRebuildTaskStatusEnum {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 未开始
|
* 执行失败
|
||||||
*/
|
*/
|
||||||
ERROR(-1),
|
ERROR(-1),
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.jeecg.common.constant.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输运任务模式说明枚举
|
||||||
|
*/
|
||||||
|
public enum TransportTaskModeEnum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正向
|
||||||
|
*/
|
||||||
|
FORWARD(-1),
|
||||||
|
/**
|
||||||
|
* 反向
|
||||||
|
*/
|
||||||
|
BACK_FORWARD(1);
|
||||||
|
|
||||||
|
private Integer key;
|
||||||
|
|
||||||
|
TransportTaskModeEnum(Integer key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getKey(){
|
||||||
|
return this.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,34 +1,34 @@
|
||||||
package org.jeecg.common.constant.enums;
|
package org.jeecg.common.constant.enums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输运任务状态说明枚举
|
* 输运模拟任务状态说明枚举
|
||||||
*/
|
*/
|
||||||
public enum TransportTaskStatusEnum {
|
public enum TransportTaskStatusEnum {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 失败
|
* 执行失败
|
||||||
*/
|
*/
|
||||||
FAILURE(-1),
|
ERROR(-1),
|
||||||
/**
|
/**
|
||||||
* 未开始
|
* 未开始
|
||||||
*/
|
*/
|
||||||
NOT_START(1),
|
NOT_STARTED(0),
|
||||||
/**
|
/**
|
||||||
* 运行中
|
* 执行中
|
||||||
*/
|
*/
|
||||||
RUNNING(2),
|
IN_OPERATION(1),
|
||||||
/**
|
/**
|
||||||
* 已完成
|
* 已完成
|
||||||
*/
|
*/
|
||||||
COMPLETED(3);
|
COMPLETED(2);
|
||||||
|
|
||||||
private Integer key;
|
private Integer value;
|
||||||
|
|
||||||
TransportTaskStatusEnum(Integer key) {
|
TransportTaskStatusEnum(Integer value) {
|
||||||
this.key = key;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getKey(){
|
public Integer getValue(){
|
||||||
return this.key;
|
return this.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,12 @@ public enum WeatherDataSourceEnum {
|
||||||
/**
|
/**
|
||||||
* T1H
|
* T1H
|
||||||
*/
|
*/
|
||||||
T1H(5,"T1H");
|
FNL(5,"FNL"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* T1H
|
||||||
|
*/
|
||||||
|
T1H(6,"T1H");
|
||||||
private Integer key;
|
private Integer key;
|
||||||
|
|
||||||
private String value;
|
private String value;
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,19 @@ public class SystemStorageProperties {
|
||||||
private String ncep;
|
private String ncep;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* T1H数据存储路径
|
* graphcast模型预测数据存储路径
|
||||||
|
*/
|
||||||
|
private String graphcast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* t1h数据存储路径
|
||||||
*/
|
*/
|
||||||
private String t1h;
|
private String t1h;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* graphcast模型预测数据存储路径
|
* fnl数据存储路径
|
||||||
*/
|
*/
|
||||||
private String graphcast;
|
private String fnl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WRF数据存储路径
|
* WRF数据存储路径
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
package org.jeecg.common.properties;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "transport-simulation")
|
||||||
|
public class TransportSimulationProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型输出路径
|
||||||
|
*/
|
||||||
|
private String outputPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数配置文件路径(和fnl气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String fnlParamConfigPath;
|
||||||
|
/**
|
||||||
|
* 参数配置文件路径(和pangu气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String panguParamConfigPath;
|
||||||
|
/**
|
||||||
|
* 参数配置文件路径(和graphcast气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String graphcastParamConfigPath;
|
||||||
|
/**
|
||||||
|
* 参数配置文件路径(和cra40气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String cra40ParamConfigPath;
|
||||||
|
/**
|
||||||
|
* 参数配置文件路径(和ncep气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String ncepParamConfigPath;
|
||||||
|
/**
|
||||||
|
* 参数配置文件路径(和T1H气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String t1hParamConfigPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 台站数据配置文件路径(和fnl气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String fnlStationsConfigPath;
|
||||||
|
/**
|
||||||
|
* 台站数据配置文件路径(和pangu气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String panguStationsConfigPath;
|
||||||
|
/**
|
||||||
|
* 台站数据配置文件路径(和graphcast气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String graphcastStationsConfigPath;
|
||||||
|
/**
|
||||||
|
* 台站数据配置文件路径(和cra40气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String cra40StationsConfigPath;
|
||||||
|
/**
|
||||||
|
* 台站数据配置文件路径(和ncep气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String ncepStationsConfigPath;
|
||||||
|
/**
|
||||||
|
* 台站数据配置文件路径(和T1H气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String t1hStationsConfigPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正演脚本路径(和fnl气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String fnlForwardScriptPath;
|
||||||
|
/**
|
||||||
|
* 正演脚本路径(和pangu气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String panguForwardScriptPath;
|
||||||
|
/**
|
||||||
|
* 正演脚本路径(和graphcast气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String graphcastForwardScriptPath;
|
||||||
|
/**
|
||||||
|
* 正演脚本路径(和cra40气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String cra40ForwardScriptPath;
|
||||||
|
/**
|
||||||
|
* 正演脚本路径(和ncep气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String ncepForwardScriptPath;
|
||||||
|
/**
|
||||||
|
* 正演脚本路径(和T1H气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String t1hForwardScriptPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 反演脚本路径(和fnl气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String fnlBackwardScriptPath;
|
||||||
|
/**
|
||||||
|
* 反演脚本路径(和pangu气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String panguBackwardScriptPath;
|
||||||
|
/**
|
||||||
|
* 反演脚本路径(和graphcast气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String graphcastBackwardScriptPath;
|
||||||
|
/**
|
||||||
|
* 反演脚本路径(和cra40气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String cra40BackwardScriptPath;
|
||||||
|
/**
|
||||||
|
* 反演脚本路径(和ncep气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String ncepBackwardScriptPath;
|
||||||
|
/**
|
||||||
|
* 反演脚本路径(和T1H气象数据有关系)
|
||||||
|
*/
|
||||||
|
private String t1hBackwardScriptPath;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -146,7 +146,7 @@ public class SourceRebuildTask implements Serializable {
|
||||||
*/
|
*/
|
||||||
@Null(message = "耗时必须为空",groups = {InsertGroup.class, UpdateGroup.class})
|
@Null(message = "耗时必须为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
@TableField(value = "time_consuming")
|
@TableField(value = "time_consuming")
|
||||||
private Integer timeConsuming;
|
private Double timeConsuming;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 半衰期
|
* 半衰期
|
||||||
|
|
|
||||||
|
|
@ -60,12 +60,26 @@ public class TransportTask{
|
||||||
private Integer taskPprogress;
|
private Integer taskPprogress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务状态(-1执行失败,1未开始,2运行中,3已完成)
|
* 任务状态(-1执行失败,0未开始,1运行中,2已完成)
|
||||||
*/
|
*/
|
||||||
@Null(message = "任务状态必须为空",groups = {InsertGroup.class, UpdateGroup.class})
|
@Null(message = "任务状态必须为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
@TableField(value = "task_status")
|
@TableField(value = "task_status")
|
||||||
private Integer taskStatus;
|
private Integer taskStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 气象数据类型(1-盘古模型,2-graphcast,3-cra40,4-ncep)
|
||||||
|
*/
|
||||||
|
@NotNull(message = "气象数据类型不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "use_met_type")
|
||||||
|
private Integer useMetType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 耗时(分钟)
|
||||||
|
*/
|
||||||
|
@Null(message = "耗时必须为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "time_consuming")
|
||||||
|
private Double timeConsuming;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建人
|
* 创建人
|
||||||
*/
|
*/
|
||||||
|
|
@ -94,6 +108,41 @@ public class TransportTask{
|
||||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模拟开始时间
|
||||||
|
*/
|
||||||
|
@NotNull(message = "模拟开始时间不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "start_time")
|
||||||
|
private Date startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模拟结束时间
|
||||||
|
*/
|
||||||
|
@NotNull(message = "模拟结束时间不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "end_time")
|
||||||
|
private Date endTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放下部高度
|
||||||
|
*/
|
||||||
|
@NotNull(message = "释放下部高度不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "z1")
|
||||||
|
private Double z1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放上部高度
|
||||||
|
*/
|
||||||
|
@NotNull(message = "释放上部高度不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "z2")
|
||||||
|
private Double z2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 粒子数量
|
||||||
|
*/
|
||||||
|
@NotNull(message = "粒子数量不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "particle_count")
|
||||||
|
private Integer particleCount;
|
||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
List<TransportTaskChild> childList;
|
List<TransportTaskChild> childList;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import jakarta.validation.constraints.Null;
|
import jakarta.validation.constraints.Null;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -35,46 +36,32 @@ public class TransportTaskChild{
|
||||||
private Integer taskId;
|
private Integer taskId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模拟开始时间
|
* 台站编目
|
||||||
*/
|
*/
|
||||||
@NotNull(message = "模拟开始时间不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
@NotBlank(message = "释放量不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
@TableField(value = "start_time")
|
@TableField(value = "station_code")
|
||||||
private Date startTime;
|
private String stationCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模拟结束时间
|
* 经度1
|
||||||
*/
|
*/
|
||||||
@NotNull(message = "模拟结束时间不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
@NotNull(message = "经度不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
@TableField(value = "end_time")
|
@TableField(value = "lon")
|
||||||
private Date endTime;
|
private Double lon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 释放下部高度
|
* 纬度1
|
||||||
*/
|
*/
|
||||||
@NotNull(message = "释放下部高度不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
@NotNull(message = "经度不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
@TableField(value = "z1")
|
@TableField(value = "lat")
|
||||||
private Double z1;
|
private Double lat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 释放上部高度
|
* 释放量
|
||||||
*/
|
*/
|
||||||
@NotNull(message = "释放上部高度不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
@NotNull(message = "释放量不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
@TableField(value = "z2")
|
@TableField(value = "release_amount")
|
||||||
private Double z2;
|
private String releaseAmount;
|
||||||
|
|
||||||
/**
|
|
||||||
* 粒子数量
|
|
||||||
*/
|
|
||||||
@NotNull(message = "粒子数量不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
|
||||||
@TableField(value = "particle_count")
|
|
||||||
private Integer particleCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 物种编号
|
|
||||||
*/
|
|
||||||
@NotNull(message = "物种编号不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
|
||||||
@TableField(value = "specnum_rel")
|
|
||||||
private Integer specnumRel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建人
|
* 创建人
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.LocalDateTime;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输运模拟任务日志表
|
* 输运模拟任务日志表
|
||||||
|
|
@ -20,15 +20,15 @@ public class TransportTaskLog implements Serializable {
|
||||||
/**
|
/**
|
||||||
* ID
|
* ID
|
||||||
*/
|
*/
|
||||||
@TableId(type = IdType.ASSIGN_ID)
|
@TableId(type = IdType.AUTO)
|
||||||
@Schema(description = "ID")
|
@Schema(description = "id")
|
||||||
private String id;
|
private Integer id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务表主键
|
* 任务表主键
|
||||||
*/
|
*/
|
||||||
@TableField(value = "task_id")
|
@TableField(value = "task_id")
|
||||||
private String taskId;
|
private Integer taskId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务运行过程日志
|
* 任务运行过程日志
|
||||||
|
|
@ -40,6 +40,5 @@ public class TransportTaskLog implements Serializable {
|
||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private LocalDateTime createTime;
|
private Date createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -51,7 +51,7 @@ public class WeatherData implements Serializable {
|
||||||
private LocalDateTime dataStartTime;
|
private LocalDateTime dataStartTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据来源(1-盘古模型,2-graphcast,3-cra40,4-ncep)
|
* 数据来源(1-盘古模型,2-graphcast,3-cra40,4-ncep,5-t1h,6-fnl)
|
||||||
*/
|
*/
|
||||||
@TableField(value = "data_source")
|
@TableField(value = "data_source")
|
||||||
private Integer dataSource;
|
private Integer dataSource;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
package org.jeecg.modules.base.entity.configuration;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("CONFIGURATION.GARDS_NUCLEARFACILITY")
|
||||||
|
public class GardsNuclearfacility implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核设施id
|
||||||
|
*/
|
||||||
|
@TableField(value = "FACILITY_ID")
|
||||||
|
private Integer facilityId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核设施名称
|
||||||
|
*/
|
||||||
|
@TableField(value = "FACILITY_NAME")
|
||||||
|
private String facilityName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核设施类型
|
||||||
|
*/
|
||||||
|
@TableField(value = "TYPE")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 地点
|
||||||
|
*/
|
||||||
|
@TableField(value = "LOCATION")
|
||||||
|
private String location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 经度
|
||||||
|
*/
|
||||||
|
@TableField(value = "LONGITUDE")
|
||||||
|
private String longitude;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 纬度
|
||||||
|
*/
|
||||||
|
@TableField(value = "LATITUDE")
|
||||||
|
private String latitude;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
@TableField(value = "STATUS")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修建时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "BUILDDATE")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
private Date buildDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 临界时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "CRITICALITYDATE")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
private Date criticalityDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退休时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "RETIREDATE")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
private Date retireDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网格工程日期
|
||||||
|
*/
|
||||||
|
@TableField(value = "GRIDCONEETIONDATE")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
private Date gridconeetionDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销售公司
|
||||||
|
*/
|
||||||
|
@TableField(value = "VENDOR")
|
||||||
|
private String vendor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拥有者
|
||||||
|
*/
|
||||||
|
@TableField(value = "OWNER")
|
||||||
|
private String owner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作人员
|
||||||
|
*/
|
||||||
|
@TableField(value = "OPERARTOR")
|
||||||
|
private String operartor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 容量
|
||||||
|
*/
|
||||||
|
@TableField(value = "CAPACITYGROSS")
|
||||||
|
private Integer capacitygross;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 容量集
|
||||||
|
*/
|
||||||
|
@TableField(value = "CAPACITYNET")
|
||||||
|
private Integer capacitynet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 热容量
|
||||||
|
*/
|
||||||
|
@TableField(value = "CAPACITYTHERMAL")
|
||||||
|
private Integer capacitythermal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 活动时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "ACTIVITY_DAY")
|
||||||
|
private Integer activityDay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 活动年份
|
||||||
|
*/
|
||||||
|
@TableField(value = "ACTIVITY_YEAR")
|
||||||
|
private Integer activityYear;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
package org.jeecg.modules.base.entity.configuration;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName(value = "CONFIGURATION.GARDS_STATIONS")
|
||||||
|
public class GardsStations implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 台站id
|
||||||
|
*/
|
||||||
|
@TableId(type = IdType.INPUT)
|
||||||
|
private Integer stationId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 台站编码
|
||||||
|
*/
|
||||||
|
@TableField(value = "STATION_CODE")
|
||||||
|
private String stationCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 城市编码
|
||||||
|
*/
|
||||||
|
@TableField(value = "COUNTRY_CODE")
|
||||||
|
private String countryCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 台站类型
|
||||||
|
*/
|
||||||
|
@TableField(value = "TYPE")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 经度
|
||||||
|
*/
|
||||||
|
@TableField(value = "LON")
|
||||||
|
private Double lon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 纬度
|
||||||
|
*/
|
||||||
|
@TableField(value = "LAT")
|
||||||
|
private Double lat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 海拔
|
||||||
|
*/
|
||||||
|
@TableField(value = "ELEVATION")
|
||||||
|
private Double elevation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 描述
|
||||||
|
*/
|
||||||
|
@TableField(value = "DESCRIPTION")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始运行日期
|
||||||
|
*/
|
||||||
|
@TableField(value = "DATE_BEGIN")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||||
|
private Date dateBegin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行终止日期
|
||||||
|
*/
|
||||||
|
@TableField(value = "DATE_END")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||||
|
private Date dateEnd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行状态
|
||||||
|
*/
|
||||||
|
@TableField(value = "STATUS")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "MODDATE")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
private Date moddate;
|
||||||
|
|
||||||
|
@TableField(value = "CATEGORY")
|
||||||
|
private Integer category;
|
||||||
|
/**
|
||||||
|
* 有效率计算类型
|
||||||
|
*/
|
||||||
|
@TableField(value = "EFFIC_CALCUL_TYPE")
|
||||||
|
private String efficCalculType;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package org.jeecg.modules.base.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.jeecg.modules.base.entity.configuration.GardsNuclearfacility;
|
||||||
|
|
||||||
|
public interface GardsNuclearfacilityMapper extends BaseMapper<GardsNuclearfacility> {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package org.jeecg.modules.base.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.jeecg.modules.base.entity.configuration.GardsStations;
|
||||||
|
|
||||||
|
public interface GardsStationsMapper extends BaseMapper<GardsStations> {
|
||||||
|
}
|
||||||
|
|
@ -73,7 +73,7 @@ public interface SourceRebuildTaskService extends IService<SourceRebuildTask> {
|
||||||
/**
|
/**
|
||||||
* 任务耗时
|
* 任务耗时
|
||||||
* @param taskId
|
* @param taskId
|
||||||
* @param taskTimeConsuming
|
* @param minute
|
||||||
*/
|
*/
|
||||||
void updateTaskTimeConsuming(Integer taskId, Integer taskTimeConsuming);
|
void updateTaskTimeConsuming(Integer taskId, Double minute);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -221,13 +221,13 @@ public class SourceRebuildTaskServiceImpl extends ServiceImpl<SourceRebuildTaskM
|
||||||
* 任务耗时
|
* 任务耗时
|
||||||
*
|
*
|
||||||
* @param taskId
|
* @param taskId
|
||||||
* @param taskTimeConsuming
|
* @param minute
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = RuntimeException.class)
|
@Transactional(rollbackFor = RuntimeException.class)
|
||||||
@Override
|
@Override
|
||||||
public void updateTaskTimeConsuming(Integer taskId, Integer taskTimeConsuming) {
|
public void updateTaskTimeConsuming(Integer taskId, Double minute) {
|
||||||
SourceRebuildTask sourceRebuildTask = this.baseMapper.selectById(taskId);
|
SourceRebuildTask sourceRebuildTask = this.baseMapper.selectById(taskId);
|
||||||
sourceRebuildTask.setTimeConsuming(taskTimeConsuming);
|
sourceRebuildTask.setTimeConsuming(minute);
|
||||||
this.updateById(sourceRebuildTask);
|
this.updateById(sourceRebuildTask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,8 +93,9 @@ public class SourceRebuildTaskExec extends Thread{
|
||||||
}finally {
|
}finally {
|
||||||
//添加任务耗时
|
//添加任务耗时
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
Integer time = Long.valueOf(stopWatch.getTime(TimeUnit.MINUTES)).intValue();
|
long seconds = stopWatch.getTime(TimeUnit.SECONDS);
|
||||||
this.sourceRebuildTaskService.updateTaskTimeConsuming(this.sourceRebuildTask.getId(),time);
|
Double min = seconds/60D;
|
||||||
|
this.sourceRebuildTaskService.updateTaskTimeConsuming(this.sourceRebuildTask.getId(),min);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
package org.jeecg.service;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
|
||||||
import org.jeecg.modules.base.entity.TransportTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 传输任务结果数据
|
|
||||||
*/
|
|
||||||
public interface TransportTaskResultService extends IService<TransportTask> {
|
|
||||||
}
|
|
||||||
|
|
@ -2,6 +2,8 @@ package org.jeecg.service;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Null;
|
||||||
import org.jeecg.common.system.query.PageRequest;
|
import org.jeecg.common.system.query.PageRequest;
|
||||||
import org.jeecg.modules.base.entity.TransportTask;
|
import org.jeecg.modules.base.entity.TransportTask;
|
||||||
import org.jeecg.modules.base.entity.TransportTaskLog;
|
import org.jeecg.modules.base.entity.TransportTaskLog;
|
||||||
|
|
@ -62,4 +64,30 @@ public interface TransportTaskService extends IService<TransportTask> {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<TransportTaskLog> getTaskLog(Integer taskId);
|
List<TransportTaskLog> getTaskLog(Integer taskId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存任务日志
|
||||||
|
* @param transportTaskLog
|
||||||
|
*/
|
||||||
|
void saveLog(TransportTaskLog transportTaskLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改任务耗时
|
||||||
|
* @param taskId
|
||||||
|
* @param minute
|
||||||
|
*/
|
||||||
|
void updateTaskTimeConsuming(Integer taskId, Double minute);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除任务日志
|
||||||
|
* @param taskId
|
||||||
|
*/
|
||||||
|
void deleteTaskLog(Integer taskId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改任务状态
|
||||||
|
* @param taskId
|
||||||
|
* @param status
|
||||||
|
*/
|
||||||
|
void updateTaskStatus(Integer taskId, Integer status);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package org.jeecg.service;
|
package org.jeecg.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
|
@ -9,6 +9,8 @@ import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jeecg.common.constant.enums.TransportTaskStatusEnum;
|
import org.jeecg.common.constant.enums.TransportTaskStatusEnum;
|
||||||
import org.jeecg.common.constant.enums.TransportTaskTypeEnum;
|
import org.jeecg.common.constant.enums.TransportTaskTypeEnum;
|
||||||
|
import org.jeecg.common.properties.SystemStorageProperties;
|
||||||
|
import org.jeecg.common.properties.TransportSimulationProperties;
|
||||||
import org.jeecg.common.system.query.PageRequest;
|
import org.jeecg.common.system.query.PageRequest;
|
||||||
import org.jeecg.modules.base.entity.TransportTask;
|
import org.jeecg.modules.base.entity.TransportTask;
|
||||||
import org.jeecg.modules.base.entity.TransportTaskChild;
|
import org.jeecg.modules.base.entity.TransportTaskChild;
|
||||||
|
|
@ -16,6 +18,9 @@ import org.jeecg.modules.base.entity.TransportTaskLog;
|
||||||
import org.jeecg.modules.base.mapper.TransportTaskChildMapper;
|
import org.jeecg.modules.base.mapper.TransportTaskChildMapper;
|
||||||
import org.jeecg.modules.base.mapper.TransportTaskLogMapper;
|
import org.jeecg.modules.base.mapper.TransportTaskLogMapper;
|
||||||
import org.jeecg.modules.base.mapper.TransportTaskMapper;
|
import org.jeecg.modules.base.mapper.TransportTaskMapper;
|
||||||
|
import org.jeecg.modules.base.mapper.WeatherDataMapper;
|
||||||
|
import org.jeecg.service.TransportTaskService;
|
||||||
|
import org.jeecg.task.TransportTaskExec;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
@ -32,6 +37,9 @@ public class TransportTaskServiceImpl extends ServiceImpl<TransportTaskMapper,Tr
|
||||||
|
|
||||||
private final TransportTaskChildMapper transportTaskChildMapper;
|
private final TransportTaskChildMapper transportTaskChildMapper;
|
||||||
private final TransportTaskLogMapper transportTaskLogMapper;
|
private final TransportTaskLogMapper transportTaskLogMapper;
|
||||||
|
private final WeatherDataMapper weatherDataMapper;
|
||||||
|
private final TransportSimulationProperties simulationProperties;
|
||||||
|
private final SystemStorageProperties systemStorageProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询任务列表
|
* 分页查询任务列表
|
||||||
|
|
@ -76,8 +84,9 @@ public class TransportTaskServiceImpl extends ServiceImpl<TransportTaskMapper,Tr
|
||||||
throw new RuntimeException("此任务已存在,请核对任务名称信息");
|
throw new RuntimeException("此任务已存在,请核对任务名称信息");
|
||||||
}
|
}
|
||||||
transportTask.setTaskPprogress(0);
|
transportTask.setTaskPprogress(0);
|
||||||
transportTask.setTaskStatus(TransportTaskStatusEnum.NOT_START.getKey());
|
transportTask.setTaskStatus(TransportTaskStatusEnum.NOT_STARTED.getValue());
|
||||||
transportTask.setTaskType(TransportTaskTypeEnum.MANUALLY.getKey());
|
transportTask.setTaskType(TransportTaskTypeEnum.MANUALLY.getKey());
|
||||||
|
transportTask.setTimeConsuming(0D);
|
||||||
this.baseMapper.insert(transportTask);
|
this.baseMapper.insert(transportTask);
|
||||||
if(CollUtil.isNotEmpty(transportTask.getChildList())){
|
if(CollUtil.isNotEmpty(transportTask.getChildList())){
|
||||||
transportTask.getChildList().forEach(transportTaskChild -> {
|
transportTask.getChildList().forEach(transportTaskChild -> {
|
||||||
|
|
@ -128,6 +137,12 @@ public class TransportTaskServiceImpl extends ServiceImpl<TransportTaskMapper,Tr
|
||||||
}
|
}
|
||||||
checkIdResult.setTaskName(transportTask.getTaskName());
|
checkIdResult.setTaskName(transportTask.getTaskName());
|
||||||
checkIdResult.setTaskMode(transportTask.getTaskMode());
|
checkIdResult.setTaskMode(transportTask.getTaskMode());
|
||||||
|
checkIdResult.setUseMetType(transportTask.getUseMetType());
|
||||||
|
checkIdResult.setStartTime(transportTask.getStartTime());
|
||||||
|
checkIdResult.setEndTime(transportTask.getEndTime());
|
||||||
|
checkIdResult.setZ1(transportTask.getZ1());
|
||||||
|
checkIdResult.setZ2(transportTask.getZ2());
|
||||||
|
checkIdResult.setParticleCount(transportTask.getParticleCount());
|
||||||
this.baseMapper.updateById(checkIdResult);
|
this.baseMapper.updateById(checkIdResult);
|
||||||
//先删除再保存
|
//先删除再保存
|
||||||
LambdaQueryWrapper<TransportTaskChild> delQueryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<TransportTaskChild> delQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
|
@ -163,7 +178,23 @@ public class TransportTaskServiceImpl extends ServiceImpl<TransportTaskMapper,Tr
|
||||||
@Transactional(rollbackFor = RuntimeException.class)
|
@Transactional(rollbackFor = RuntimeException.class)
|
||||||
@Override
|
@Override
|
||||||
public void runTask(Integer id) {
|
public void runTask(Integer id) {
|
||||||
|
//校验任务
|
||||||
|
TransportTask checkIdResult = this.baseMapper.selectById(id);
|
||||||
|
if(Objects.isNull(checkIdResult)){
|
||||||
|
throw new RuntimeException("此任务不存在");
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<TransportTaskChild> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(TransportTaskChild::getTaskId,id);
|
||||||
|
List<TransportTaskChild> transportTaskChildren = transportTaskChildMapper.selectList(queryWrapper);
|
||||||
|
if(Objects.isNull(transportTaskChildren)){
|
||||||
|
throw new RuntimeException("此任务对应的flexpart模型配置信息不存在,请确认");
|
||||||
|
}
|
||||||
|
TransportTaskExec taskExec = new TransportTaskExec();
|
||||||
|
taskExec.init(weatherDataMapper,this,
|
||||||
|
checkIdResult,transportTaskChildren,
|
||||||
|
simulationProperties,systemStorageProperties);
|
||||||
|
taskExec.setName("输运模拟执行线程");
|
||||||
|
taskExec.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -178,4 +209,58 @@ public class TransportTaskServiceImpl extends ServiceImpl<TransportTaskMapper,Tr
|
||||||
queryWrapper.eq(TransportTaskLog::getTaskId,taskId);
|
queryWrapper.eq(TransportTaskLog::getTaskId,taskId);
|
||||||
return transportTaskLogMapper.selectList(queryWrapper);
|
return transportTaskLogMapper.selectList(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存任务日志
|
||||||
|
*
|
||||||
|
* @param transportTaskLog
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = RuntimeException.class)
|
||||||
|
@Override
|
||||||
|
public void saveLog(TransportTaskLog transportTaskLog) {
|
||||||
|
transportTaskLogMapper.insert(transportTaskLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改任务耗时
|
||||||
|
*
|
||||||
|
* @param taskId
|
||||||
|
* @param minute
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = RuntimeException.class)
|
||||||
|
@Override
|
||||||
|
public void updateTaskTimeConsuming(Integer taskId, Double minute) {
|
||||||
|
TransportTask transportTask = this.baseMapper.selectById(taskId);
|
||||||
|
transportTask.setTimeConsuming(minute);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除任务日志
|
||||||
|
*
|
||||||
|
* @param taskId
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = RuntimeException.class)
|
||||||
|
@Override
|
||||||
|
public void deleteTaskLog(Integer taskId) {
|
||||||
|
LambdaQueryWrapper<TransportTaskLog> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(TransportTaskLog::getTaskId,taskId);
|
||||||
|
transportTaskLogMapper.delete(queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改任务状态
|
||||||
|
* @param taskId
|
||||||
|
* @param status
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = RuntimeException.class)
|
||||||
|
@Override
|
||||||
|
public void updateTaskStatus(Integer taskId, Integer status) {
|
||||||
|
TransportTask transportTask = this.baseMapper.selectById(taskId);
|
||||||
|
if(Objects.isNull(transportTask)){
|
||||||
|
throw new RuntimeException("此任务不存在");
|
||||||
|
}
|
||||||
|
transportTask.setTaskStatus(status);
|
||||||
|
this.baseMapper.updateById(transportTask);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package org.jeecg.task;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志事件
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class ProgressEvent implements Serializable{
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Integer taskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过程日志
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
public ProgressEvent(Integer taskId, String content) {
|
||||||
|
this.taskId = taskId;
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package org.jeecg.task;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.modules.base.entity.TransportTaskLog;
|
||||||
|
import org.jeecg.service.TransportTaskService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志监测线程
|
||||||
|
* @author 86187
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class ProgressMonitor{
|
||||||
|
|
||||||
|
private final TransportTaskService transportTaskService;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void start() {
|
||||||
|
ProgressMonitorThread monitor = new ProgressMonitorThread();
|
||||||
|
monitor.setName("输运模拟日志监测线程");
|
||||||
|
monitor.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ProgressMonitorThread extends Thread{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for(;;) {
|
||||||
|
try {
|
||||||
|
ProgressEvent event = ProgressQueue.getInstance().take();
|
||||||
|
if(Objects.nonNull(event)) {
|
||||||
|
TransportTaskLog log = new TransportTaskLog();
|
||||||
|
log.setTaskId(event.getTaskId());
|
||||||
|
log.setLogContent(event.getContent());
|
||||||
|
transportTaskService.saveLog(log);
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("输运模拟日志存储线程异常,日志存储失败,原因为:{}",e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package org.jeecg.task;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志队列
|
||||||
|
*/
|
||||||
|
public class ProgressQueue {
|
||||||
|
|
||||||
|
private final LinkedList<ProgressEvent> queue = new LinkedList<>();
|
||||||
|
|
||||||
|
private static ProgressQueue progressQueue = new ProgressQueue();
|
||||||
|
|
||||||
|
public static ProgressQueue getInstance() {
|
||||||
|
return progressQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void offer(ProgressEvent event) {
|
||||||
|
synchronized (queue) {
|
||||||
|
queue.addLast(event);
|
||||||
|
queue.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgressEvent take(){
|
||||||
|
synchronized (queue) {
|
||||||
|
if(queue.isEmpty()) {
|
||||||
|
try {
|
||||||
|
queue.wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ProgressEvent event = queue.removeFirst();
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,294 @@
|
||||||
|
package org.jeecg.task;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import org.apache.commons.lang3.time.StopWatch;
|
||||||
|
import org.apache.logging.log4j.util.Strings;
|
||||||
|
import org.jeecg.common.constant.enums.TransportTaskModeEnum;
|
||||||
|
import org.jeecg.common.constant.enums.TransportTaskStatusEnum;
|
||||||
|
import org.jeecg.common.constant.enums.WeatherDataSourceEnum;
|
||||||
|
import org.jeecg.common.properties.SystemStorageProperties;
|
||||||
|
import org.jeecg.common.properties.TransportSimulationProperties;
|
||||||
|
import org.jeecg.modules.base.entity.*;
|
||||||
|
import org.jeecg.modules.base.mapper.WeatherDataMapper;
|
||||||
|
import org.jeecg.service.TransportTaskService;
|
||||||
|
import java.io.*;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class TransportTaskExec extends Thread{
|
||||||
|
|
||||||
|
private WeatherDataMapper weatherDataMapper;
|
||||||
|
private TransportTaskService transportTaskService;
|
||||||
|
private TransportTask transportTask;
|
||||||
|
private List<TransportTaskChild> transportTaskChildren;
|
||||||
|
private TransportSimulationProperties simulationProperties;
|
||||||
|
private SystemStorageProperties systemStorageProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
|
public void init(WeatherDataMapper weatherDataMapper,
|
||||||
|
TransportTaskService transportTaskService,
|
||||||
|
TransportTask transportTask,
|
||||||
|
List<TransportTaskChild> transportTaskChildren,
|
||||||
|
TransportSimulationProperties simulationProperties,
|
||||||
|
SystemStorageProperties systemStorageProperties){
|
||||||
|
this.weatherDataMapper = weatherDataMapper;
|
||||||
|
this.transportTaskService = transportTaskService;
|
||||||
|
this.transportTask = transportTask;
|
||||||
|
this.transportTaskChildren = transportTaskChildren;
|
||||||
|
this.simulationProperties = simulationProperties;
|
||||||
|
this.systemStorageProperties = systemStorageProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
this.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行任务
|
||||||
|
*/
|
||||||
|
public void execute() {
|
||||||
|
StopWatch stopWatch = new StopWatch();
|
||||||
|
stopWatch.start();
|
||||||
|
try{
|
||||||
|
//修改任务状态为执行中
|
||||||
|
this.transportTaskService.updateTaskStatus(this.transportTask.getId(), TransportTaskStatusEnum.IN_OPERATION.getValue());
|
||||||
|
//如果此任务已存在历史日志,先清除
|
||||||
|
this.transportTaskService.deleteTaskLog(this.transportTask.getId());
|
||||||
|
//检查气象数据
|
||||||
|
this.checkMetData();
|
||||||
|
//执行模拟
|
||||||
|
this.execSimulation();
|
||||||
|
}catch (Exception e){
|
||||||
|
String taskErrorLog = "任务执行失败,原因:"+e.getMessage();
|
||||||
|
ProgressQueue.getInstance().offer(new ProgressEvent(this.transportTask.getId(),taskErrorLog));
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}finally {
|
||||||
|
//添加任务耗时
|
||||||
|
stopWatch.stop();
|
||||||
|
long seconds = stopWatch.getTime(TimeUnit.SECONDS);
|
||||||
|
Double min = seconds/60D;
|
||||||
|
this.transportTaskService.updateTaskTimeConsuming(this.transportTask.getId(),min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查气象数据
|
||||||
|
*/
|
||||||
|
private void checkMetData(){
|
||||||
|
String msg = "检查气象数据";
|
||||||
|
ProgressQueue.getInstance().offer(new ProgressEvent(this.transportTask.getId(),msg));
|
||||||
|
|
||||||
|
LocalDateTime startTime = this.transportTask.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||||
|
LocalDateTime endTime = this.transportTask.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||||
|
startTime = startTime.minusDays(3);
|
||||||
|
endTime = endTime.plusDays(3);
|
||||||
|
LambdaQueryWrapper<WeatherData> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(WeatherData::getDataSource,this.transportTask.getUseMetType());
|
||||||
|
queryWrapper.between(WeatherData::getDataStartTime,startTime,endTime);
|
||||||
|
List<WeatherData> dataList = weatherDataMapper.selectList(queryWrapper);
|
||||||
|
long days = ChronoUnit.DAYS.between(startTime, endTime);
|
||||||
|
//一天至少4个气象数据,至少是00,06,12,18
|
||||||
|
// if(CollUtil.isEmpty(dataList) || dataList.size() < (days*4)){
|
||||||
|
// String exceptionMsg = "此任务时间范围(%s - %s)参数所涉及的气象数据不完整,请核对气象数据";
|
||||||
|
// String formatMsg = String.format(exceptionMsg, LocalDateTimeUtil.format(startTime, "yyyy-MM-dd hh:mm:ss"), LocalDateTimeUtil.format(endTime, "yyyy-MM-dd hh:mm:ss"));
|
||||||
|
// ProgressQueue.getInstance().offer(new ProgressEvent(this.transportTask.getId(),formatMsg));
|
||||||
|
// throw new RuntimeException(formatMsg);
|
||||||
|
// }
|
||||||
|
String finalMsg = "检查气象数据完毕";
|
||||||
|
ProgressQueue.getInstance().offer(new ProgressEvent(this.transportTask.getId(),finalMsg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行模拟
|
||||||
|
*/
|
||||||
|
private void execSimulation(){
|
||||||
|
Process process = null;
|
||||||
|
try {
|
||||||
|
String paramMsg = "生成flexpart所需参数文件:param.config,stations.config";
|
||||||
|
ProgressQueue.getInstance().offer(new ProgressEvent(this.transportTask.getId(),paramMsg));
|
||||||
|
//处理参数配置文件
|
||||||
|
String paramConfigPath = this.getParamConfigPath(this.transportTask.getUseMetType());
|
||||||
|
String metDataPath = this.getMetDataPath(this.transportTask.getUseMetType());
|
||||||
|
if(!FileUtil.exist(paramConfigPath)){
|
||||||
|
FileUtil.touch(paramConfigPath);
|
||||||
|
}
|
||||||
|
StringBuilder paramContent = new StringBuilder();
|
||||||
|
paramContent.append(DateUtil.format(this.transportTask.getStartTime(),"yyyyMMdd")).append("\n");
|
||||||
|
paramContent.append(DateUtil.format(this.transportTask.getEndTime(),"yyyyMMdd")).append("\n");
|
||||||
|
paramContent.append(DateUtil.format(this.transportTask.getStartTime(),"HHmmss")).append("\n");
|
||||||
|
paramContent.append(DateUtil.format(this.transportTask.getEndTime(),"HHmmss")).append("\n");
|
||||||
|
paramContent.append(this.transportTask.getZ1()).append("\n");
|
||||||
|
paramContent.append(this.transportTask.getZ2()).append("\n");
|
||||||
|
paramContent.append(metDataPath).append("\n");
|
||||||
|
FileUtil.writeString(paramContent.toString(),paramConfigPath,"UTF-8");
|
||||||
|
//处理台站数据文件
|
||||||
|
List<String> stationConfigInfo = new ArrayList<>();
|
||||||
|
String stationsConfigPath = this.getStationsConfigPath(this.transportTask.getUseMetType());
|
||||||
|
if(!FileUtil.exist(stationsConfigPath)){
|
||||||
|
FileUtil.touch(stationsConfigPath);
|
||||||
|
}
|
||||||
|
this.transportTaskChildren.forEach(taskChild -> {
|
||||||
|
String format = "%s,%f,%f,%s";
|
||||||
|
String row = String.format(format,taskChild.getStationCode(),taskChild.getLat(),taskChild.getLon(),taskChild.getReleaseAmount());
|
||||||
|
stationConfigInfo.add(row);
|
||||||
|
});
|
||||||
|
FileUtil.writeLines(stationConfigInfo,stationsConfigPath,"UTF-8");
|
||||||
|
//获取脚本路径
|
||||||
|
String scriptPath = null;
|
||||||
|
if(TransportTaskModeEnum.FORWARD.getKey().equals(this.transportTask.getTaskMode())){
|
||||||
|
scriptPath = this.getForwardScriptPath(this.transportTask.getUseMetType());
|
||||||
|
} else if (TransportTaskModeEnum.BACK_FORWARD.getKey().equals(this.transportTask.getTaskMode())) {
|
||||||
|
scriptPath = this.getBackForwardScriptPath(this.transportTask.getUseMetType());
|
||||||
|
}
|
||||||
|
String execScriptMsg = "执行任务脚本,开始模拟,路径为:"+scriptPath;
|
||||||
|
ProgressQueue.getInstance().offer(new ProgressEvent(this.transportTask.getId(),execScriptMsg));
|
||||||
|
ProcessBuilder processBuilder = new ProcessBuilder(scriptPath);
|
||||||
|
processBuilder.directory(new File(new File(scriptPath).getParent()));
|
||||||
|
processBuilder.redirectErrorStream(true);
|
||||||
|
process = processBuilder.start();
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
|
||||||
|
//读取输出日志
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
if(StrUtil.isNotBlank(line)){
|
||||||
|
ProgressQueue.getInstance().offer(new ProgressEvent(this.transportTask.getId(),line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//等待进程结束
|
||||||
|
process.waitFor();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}finally {
|
||||||
|
if(Objects.nonNull(process)){
|
||||||
|
process.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取气象数据路径
|
||||||
|
* @param dataSource
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String getMetDataPath(Integer dataSource){
|
||||||
|
StringBuilder path = new StringBuilder();
|
||||||
|
path.append(systemStorageProperties.getRootPath());
|
||||||
|
path.append(File.separator);
|
||||||
|
if(WeatherDataSourceEnum.PANGU.getKey().equals(dataSource)){
|
||||||
|
path.append(systemStorageProperties.getPangu());
|
||||||
|
}else if(WeatherDataSourceEnum.GRAPHCAST.getKey().equals(dataSource)){
|
||||||
|
path.append(systemStorageProperties.getGraphcast());
|
||||||
|
}else if(WeatherDataSourceEnum.CRA40.getKey().equals(dataSource)){
|
||||||
|
path.append(systemStorageProperties.getCra40());
|
||||||
|
}else if(WeatherDataSourceEnum.NCEP.getKey().equals(dataSource)){
|
||||||
|
path.append(systemStorageProperties.getNcep());
|
||||||
|
}else if(WeatherDataSourceEnum.FNL.getKey().equals(dataSource)){
|
||||||
|
path.append(systemStorageProperties.getFnl());
|
||||||
|
}else if(WeatherDataSourceEnum.T1H.getKey().equals(dataSource)){
|
||||||
|
path.append(systemStorageProperties.getT1h());
|
||||||
|
}
|
||||||
|
return path.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取参数配置文件路径
|
||||||
|
* @param dataSource
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String getParamConfigPath(Integer dataSource){
|
||||||
|
if(WeatherDataSourceEnum.PANGU.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getPanguParamConfigPath();
|
||||||
|
}else if(WeatherDataSourceEnum.GRAPHCAST.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getGraphcastParamConfigPath();
|
||||||
|
}else if(WeatherDataSourceEnum.CRA40.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getCra40ParamConfigPath();
|
||||||
|
}else if(WeatherDataSourceEnum.NCEP.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getNcepParamConfigPath();
|
||||||
|
}else if(WeatherDataSourceEnum.FNL.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getFnlParamConfigPath();
|
||||||
|
}else if(WeatherDataSourceEnum.T1H.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getT1hParamConfigPath();
|
||||||
|
}
|
||||||
|
return Strings.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取台站参数配置文件路径
|
||||||
|
* @param dataSource
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String getStationsConfigPath(Integer dataSource){
|
||||||
|
if(WeatherDataSourceEnum.PANGU.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getPanguStationsConfigPath();
|
||||||
|
}else if(WeatherDataSourceEnum.GRAPHCAST.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getCra40StationsConfigPath();
|
||||||
|
}else if(WeatherDataSourceEnum.CRA40.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getCra40StationsConfigPath();
|
||||||
|
}else if(WeatherDataSourceEnum.NCEP.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getNcepStationsConfigPath();
|
||||||
|
}else if(WeatherDataSourceEnum.FNL.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getFnlStationsConfigPath();
|
||||||
|
}else if(WeatherDataSourceEnum.T1H.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getT1hStationsConfigPath();
|
||||||
|
}
|
||||||
|
return Strings.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取正演脚本路径
|
||||||
|
* @param dataSource
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String getForwardScriptPath(Integer dataSource){
|
||||||
|
if(WeatherDataSourceEnum.PANGU.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getPanguForwardScriptPath();
|
||||||
|
}else if(WeatherDataSourceEnum.GRAPHCAST.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getGraphcastForwardScriptPath();
|
||||||
|
}else if(WeatherDataSourceEnum.CRA40.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getCra40ForwardScriptPath();
|
||||||
|
}else if(WeatherDataSourceEnum.NCEP.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getNcepForwardScriptPath();
|
||||||
|
}else if(WeatherDataSourceEnum.FNL.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getFnlForwardScriptPath();
|
||||||
|
}else if(WeatherDataSourceEnum.T1H.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getT1hForwardScriptPath();
|
||||||
|
}
|
||||||
|
return Strings.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取正演脚本路径
|
||||||
|
* @param dataSource
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String getBackForwardScriptPath(Integer dataSource){
|
||||||
|
if(WeatherDataSourceEnum.PANGU.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getPanguBackwardScriptPath();
|
||||||
|
}else if(WeatherDataSourceEnum.GRAPHCAST.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getGraphcastBackwardScriptPath();
|
||||||
|
}else if(WeatherDataSourceEnum.CRA40.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getCra40BackwardScriptPath();
|
||||||
|
}else if(WeatherDataSourceEnum.NCEP.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getNcepBackwardScriptPath();
|
||||||
|
}else if(WeatherDataSourceEnum.FNL.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getFnlBackwardScriptPath();
|
||||||
|
}else if(WeatherDataSourceEnum.T1H.getKey().equals(dataSource)){
|
||||||
|
return simulationProperties.getT1hBackwardScriptPath();
|
||||||
|
}
|
||||||
|
return Strings.EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user