提交 87df2a26 作者: 涂茂林

feat:报警扫描

上级 52704c34
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 9:32
*/
@Component
public class AllowEntranceStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public AllowEntranceStrategy() {
Integer relevanceParam = RelevanceParamEnum.ALLOW_ENTRANCE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndUserParam> timeAndUser = ruleParam.getTimeAndUser();
if (CollectionUtils.isEmpty(timeAndUser)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条允许进入人员的规则");
}
for (TimeAndUserParam item : timeAndUser) {
if (CollectionUtils.isEmpty(item.getUser())) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一个允许进入的人员");
}
}
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.param.location.rule.*;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 最多人数校验
* @author tml
* @version 1.0
* @date 2022/4/29 9:28
*/
@Component
public class MaxPeopleNumberStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public MaxPeopleNumberStrategy() {
Integer relevanceParam = RelevanceParamEnum.MAX_PEOPLE_NUMBER.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndNumberParam> timeAndNumber = ruleParam.getTimeAndNumber();
if (CollectionUtils.isEmpty(timeAndNumber)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条最多人数的规则");
}
for (TimeAndNumberParam item : timeAndNumber) {
if (item.getNumber() == null || item.getNumber() < 0) {
item.setNumber(0);
}
if (item.getBeginTime() == null || item.getEndTime() == null) {
item.setBeginTime(null);
item.setEndTime(null);
}
}
//将时间和距离都设为-1
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ArrayList<TimeAndUserParam> list = new ArrayList<>();
ruleParam.setTimeAndUser(list);
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 9:32
*/
@Component
public class NotAllowLeaveStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public NotAllowLeaveStrategy() {
Integer relevanceParam = RelevanceParamEnum.NOT_ALLOW_LEAVE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndUserParam> timeAndUser = ruleParam.getTimeAndUser();
if (CollectionUtils.isEmpty(timeAndUser)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条不允许离开人员的规则");
}
for (TimeAndUserParam item : timeAndUser) {
if (CollectionUtils.isEmpty(item.getUser())) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一个不允许离开的人员");
}
}
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.util.ArrayList;
import org.springframework.stereotype.Component;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 9:33
*/
@Component
public class RetentionDurationStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public RetentionDurationStrategy() {
Integer relevanceParam = RelevanceParamEnum.RETENTION_DURATION.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
if (ruleParam.getDuration() == null || ruleParam.getDuration() < 0) {
return Result.no(Status.EXPECTATION_FAILED, "滞留时长异常");
}
ruleParam.setDistance(-1);
ruleParam.setTimeAndUser(new ArrayList<>());
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check;
package com.yiring.app.design.strategy;
import com.yiring.common.core.Result;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
/**
* 扫描是否满足报警策略
* @author tml
* @version 1.0
* @date 2022/5/14 11:05
*/
public interface IScanAlarmStrategy {
/**
* 判断是否触发报警
* @param param 参数
* @return 需要报警的报警信息
*/
LocationFenceJobVo scanAlarm(LocationFenceJobParam param);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.fence;
package com.yiring.app.design.strategy.fence;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.common.core.Result;
import org.springframework.stereotype.Component;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.fence;
package com.yiring.app.design.strategy.fence;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.common.core.Result;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.fence;
package com.yiring.app.design.strategy.fence;
import com.yiring.app.constant.alarm.FenceTypeEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.common.core.Result;
import java.util.concurrent.ConcurrentHashMap;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.LocationFence;
import com.yiring.app.domain.location.LocationFenceAlarm;
import com.yiring.app.domain.location.LocationTag;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RelevanceUserParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.app.util.TimeUtil;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 允许进入人员相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:32
*/
@Component
public class AllowEntranceStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
public AllowEntranceStrategy() {
Integer relevanceParam = RelevanceParamEnum.ALLOW_ENTRANCE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndUserParam> timeAndUser = ruleParam.getTimeAndUser();
if (CollectionUtils.isEmpty(timeAndUser)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条允许进入人员的规则");
}
for (TimeAndUserParam item : timeAndUser) {
if (CollectionUtils.isEmpty(item.getUser())) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一个允许进入的人员");
}
}
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
List<TimeAndUserParam> timeAndUserParamList = rule.getTimeAndUser();
TimeAndUserParam timeAndUserParam = null;
//筛选在当前时间生效的配置
for (TimeAndUserParam item : timeAndUserParamList) {
if (TimeUtil.judgeTime(LocalDateTime.now(), item.getBeginTime(), item.getEndTime())) {
timeAndUserParam = item;
break;
}
}
//如果不在配置的时间内,则将报警记录中的状态刷新为结束,并且需要添加的报警为空
if (timeAndUserParam == null) {
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
//筛选出围栏内允许进入人员之外的人
Set<String> uuids = timeAndUserParam
.getUser()
.stream()
.map(RelevanceUserParam::getUuid)
.collect(Collectors.toSet());
List<LocationFenceAlarm> newAlarms = tagSet
.stream()
.filter(e -> !uuids.contains(e.getUser().getUuid()))
.map(e -> {
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
return LocationFenceAlarm
.builder()
.fence(fence)
.point(e.getPoint())
.areaId(mapId)
.user(e.getUser())
.tag(e)
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
})
.collect(Collectors.toList());
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.check.fence.LocationFenceTypeContext;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.fence.LocationFenceTypeContext;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.*;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndNumberParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.app.util.TimeUtil;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 最多人数相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:28
*/
@Component
public class MaxPeopleNumberStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
@Resource
private LocationTurnoverRepository locationTurnoverRepository;
public MaxPeopleNumberStrategy() {
Integer relevanceParam = RelevanceParamEnum.MAX_PEOPLE_NUMBER.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
ScanAlarmContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndNumberParam> timeAndNumber = ruleParam.getTimeAndNumber();
if (CollectionUtils.isEmpty(timeAndNumber)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条最多人数的规则");
}
for (TimeAndNumberParam item : timeAndNumber) {
if (item.getNumber() == null || item.getNumber() < 0) {
item.setNumber(0);
}
if (item.getBeginTime() == null || item.getEndTime() == null) {
item.setBeginTime(null);
item.setEndTime(null);
}
}
//将时间和距离都设为-1
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ArrayList<TimeAndUserParam> list = new ArrayList<>();
ruleParam.setTimeAndUser(list);
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
List<TimeAndNumberParam> timeAndNumberParamList = rule.getTimeAndNumber();
TimeAndNumberParam timeAndNumberParam = null;
//筛选在当前时间生效的配置
for (TimeAndNumberParam item : timeAndNumberParamList) {
if (TimeUtil.judgeTime(LocalDateTime.now(), item.getBeginTime(), item.getEndTime())) {
timeAndNumberParam = item;
break;
}
}
//如果现在不在配置的时间内,或围栏中的人少于配置的最大人数,则将报警记录中的状态刷新为结束,并且需要添加的报警为空
if (timeAndNumberParam == null || tagSet.size() <= timeAndNumberParam.getNumber()) {
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
//多出的人数
int exceed = tagSet.size() - timeAndNumberParam.getNumber();
List<LocationFenceAlarm> newAlarms = new ArrayList<>();
//查询围栏内人员进入时的信息
String beginTime = timeAndNumberParam.getBeginTime();
String endTime = timeAndNumberParam.getEndTime();
List<LocationTurnover> turnoverList = locationTurnoverRepository.withinFence(fenceId, true);
//筛选出在配置时间段内进入的进出信息
turnoverList =
turnoverList
.stream()
.filter(e -> TimeUtil.judgeTime(e.getTime(), beginTime, endTime))
.sorted(Comparator.comparing(LocationTurnover::getTime).reversed())
.collect(Collectors.toList());
//记录触发报警的信息(例如最大人数是3,那么前三个员工进入的不会记录)
for (int i = 0; i < exceed; i++) {
LocationTurnover turnover = turnoverList.get(i);
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
LocationFenceAlarm locationFenceAlarm = LocationFenceAlarm
.builder()
.fence(fence)
.point(turnover.getTag().getPoint())
.areaId(mapId)
.user(turnover.getTag().getUser())
.tag(turnover.getTag())
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
newAlarms.add(locationFenceAlarm);
}
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.*;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndNumberParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.app.util.TimeUtil;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 最少人数相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:31
*/
@Component
public class MinPeopleNumberStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public class MinPeopleNumberStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
@Resource
private LocationTurnoverRepository locationTurnoverRepository;
public MinPeopleNumberStrategy() {
Integer relevanceParam = RelevanceParamEnum.MIN_PEOPLE_NUMBER.getCode();
......@@ -50,4 +65,73 @@ public class MinPeopleNumberStrategy implements IParamInitStrategy<LocationFence
ruleParam.setTimeAndUser(list);
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
List<TimeAndNumberParam> timeAndNumberParamList = rule.getTimeAndNumber();
TimeAndNumberParam timeAndNumberParam = null;
//筛选在当前时间生效的配置
for (TimeAndNumberParam item : timeAndNumberParamList) {
if (TimeUtil.judgeTime(LocalDateTime.now(), item.getBeginTime(), item.getEndTime())) {
timeAndNumberParam = item;
break;
}
}
//如果现在不在配置的时间内,或围栏中的人大于配置的最小人数,则将报警记录中的状态刷新为结束,并且需要添加的报警为空
if (timeAndNumberParam == null || param.getTagSet().size() >= timeAndNumberParam.getNumber()) {
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
//少的人数
int missing = timeAndNumberParam.getNumber() - tagSet.size();
List<LocationFenceAlarm> newAlarms = new ArrayList<>();
//查询出这个围栏的信息
String beginTime = timeAndNumberParam.getBeginTime();
String endTime = timeAndNumberParam.getEndTime();
List<LocationTurnover> turnoverList = locationTurnoverRepository.withinFence(fenceId, false);
//筛选出在配置时间段内出这个围栏的进出信息
turnoverList =
turnoverList
.stream()
.filter(e -> TimeUtil.judgeTime(e.getTime(), beginTime, endTime))
.sorted(Comparator.comparing(LocationTurnover::getTime).reversed())
.collect(Collectors.toList());
//记录触发报警的信息(例如最小人数是3,这段时间一开始有6个人在围栏,然后出去的4个,那么只有第四个人出去才会记录)
for (int i = 0; i < missing; i++) {
LocationTurnover turnover = turnoverList.get(i);
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
LocationFenceAlarm locationFenceAlarm = LocationFenceAlarm
.builder()
.fence(fence)
.point(turnover.getTag().getPoint())
.areaId(mapId)
.user(turnover.getTag().getUser())
.tag(turnover.getTag())
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
newAlarms.add(locationFenceAlarm);
}
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.*;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RelevanceUserParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.app.util.TimeUtil;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 不允许离开人员相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:32
*/
@Component
public class NotAllowLeaveStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
@Resource
private LocationTurnoverRepository locationTurnoverRepository;
public NotAllowLeaveStrategy() {
Integer relevanceParam = RelevanceParamEnum.NOT_ALLOW_LEAVE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndUserParam> timeAndUser = ruleParam.getTimeAndUser();
if (CollectionUtils.isEmpty(timeAndUser)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条不允许离开人员的规则");
}
for (TimeAndUserParam item : timeAndUser) {
if (CollectionUtils.isEmpty(item.getUser())) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一个不允许离开的人员");
}
}
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
List<TimeAndUserParam> timeAndUserParamList = rule.getTimeAndUser();
TimeAndUserParam timeAndUserParam = null;
//筛选在当前时间生效的配置
for (TimeAndUserParam item : timeAndUserParamList) {
if (TimeUtil.judgeTime(LocalDateTime.now(), item.getBeginTime(), item.getEndTime())) {
timeAndUserParam = item;
break;
}
}
//如果不在配置的时间内,则将报警记录中的状态刷新为结束,并且需要添加的报警为空
if (timeAndUserParam == null) {
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
String beginTime = timeAndUserParam.getBeginTime();
String endTime = timeAndUserParam.getEndTime();
//筛选出在配置时间段内出这个围栏的进出信息
List<LocationTurnover> turnoverList = locationTurnoverRepository.withinFence(fenceId, false);
//筛选出在配置时间段内出这个围栏的进出信息
turnoverList =
turnoverList
.stream()
.filter(e -> TimeUtil.judgeTime(e.getTime(), beginTime, endTime))
.sorted(Comparator.comparing(LocationTurnover::getTime).reversed())
.collect(Collectors.toList());
//筛选出离开围栏的人员是不允许离开的人员
Set<String> uuids = timeAndUserParam
.getUser()
.stream()
.map(RelevanceUserParam::getUuid)
.collect(Collectors.toSet());
List<LocationFenceAlarm> newAlarms = turnoverList
.stream()
.filter(e -> uuids.contains(e.getTag().getUser().getUuid()))
.map(e -> {
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
return LocationFenceAlarm
.builder()
.fence(fence)
.point(e.getTag().getPoint())
.areaId(mapId)
.user(e.getTag().getUser())
.tag(e.getTag())
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
})
.collect(Collectors.toList());
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.*;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 滞留时长相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:33
*/
@Component
public class RetentionDurationStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
@Resource
private LocationTurnoverRepository locationTurnoverRepository;
public RetentionDurationStrategy() {
Integer relevanceParam = RelevanceParamEnum.RETENTION_DURATION.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
if (ruleParam.getDuration() == null || ruleParam.getDuration() < 0) {
return Result.no(Status.EXPECTATION_FAILED, "滞留时长异常");
}
ruleParam.setDistance(-1);
ruleParam.setTimeAndUser(new ArrayList<>());
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
//查询出最新进入该围栏的标签,计算从进入到现在滞留了多长时间,筛选出超过配置的滞留时长的人员
List<LocationTurnover> turnoverList = locationTurnoverRepository.withinFence(fenceId, true);
LocalDateTime time = LocalDateTime.now().minusMinutes(rule.getDuration());
List<LocationFenceAlarm> newAlarms = turnoverList
.stream()
.filter(e -> e.getTime().isBefore(time))
.map(e -> {
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
return LocationFenceAlarm
.builder()
.fence(fence)
.point(e.getTag().getPoint())
.areaId(mapId)
.user(e.getTag().getUser())
.tag(e.getTag())
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
})
.collect(Collectors.toList());
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import java.util.concurrent.ConcurrentHashMap;
import lombok.extern.slf4j.Slf4j;
/**
* @author tml
* @version 1.0
* @date 2022/5/14 17:51
*/
@Slf4j
public class ScanAlarmContext {
public static final ConcurrentHashMap<Integer, IScanAlarmStrategy> MAP = new ConcurrentHashMap<>(10);
public static void register(Integer relevanceParam, IScanAlarmStrategy strategy) {
MAP.put(relevanceParam, strategy);
}
public static LocationFenceJobVo scanAlarm(Integer relevanceParam, LocationFenceJobParam param) {
if (
relevanceParam == null || relevanceParam > RelevanceParamEnum.MAX || relevanceParam < RelevanceParamEnum.MIN
) {
log.warn("ScanAlarmContext.scanAlarm报警类型的关联参数异常, relevanceParam:[{}]", relevanceParam);
throw new RuntimeException("报警类型的关联参数异常");
}
IScanAlarmStrategy strategy = MAP.get(relevanceParam);
return strategy.scanAlarm(param);
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.common.core.Result;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.common.core.Result;
......
......@@ -2,8 +2,12 @@
package com.yiring.app.domain.location;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
/**
......@@ -14,4 +18,14 @@ import org.springframework.stereotype.Repository;
@Repository
public interface LocationFenceAlarmRepository
extends JpaRepository<LocationFenceAlarm, Serializable>, JpaSpecificationExecutor<LocationFenceAlarm> {}
extends JpaRepository<LocationFenceAlarm, Serializable>, JpaSpecificationExecutor<LocationFenceAlarm> {
/**
* 批量关闭报警状态
* @param ids id集
* @param now 当前时间
* @return 修改量
*/
@Query("UPDATE LocationFenceAlarm SET status = 'OVER', updateTime = ?2 WHERE id IN(?1)")
@Modifying
int batchOver(List<Long> ids, LocalDateTime now);
}
......@@ -40,6 +40,14 @@ public interface LocationFenceRepository
List<LocationFence> findLikeName(String name);
/**
* 根据启用条件查询电子围栏
* @param enable 是否启用
* @return 单子围栏信息
*/
@Query("SELECT f FROM LocationFence f WHERE f.enable = ?1 AND deleted = false")
List<LocationFence> findAllByEnable(boolean enable);
/**
* 查询空间信息在围栏内的围栏信息
* @param areaId 地图区域 id
* @param geometry 空间信息
......
......@@ -2,8 +2,10 @@
package com.yiring.app.domain.location;
import java.io.Serializable;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
/**
......@@ -14,4 +16,15 @@ import org.springframework.stereotype.Repository;
@Repository
public interface LocationTurnoverRepository
extends JpaRepository<LocationTurnover, Serializable>, JpaSpecificationExecutor<LocationTurnover> {}
extends JpaRepository<LocationTurnover, Serializable>, JpaSpecificationExecutor<LocationTurnover> {
/**
* 查询进入围栏状态为最新的所有
* @param fenceId 围栏id
* @param enter 是否是进入
* @return 所有信息
*/
@Query(
"SELECT l FROM LocationTurnover l WHERE l.sourceId = ?1 AND l.type = 'FENCE' AND l.enter = ?2 AND l.isLatest = true"
)
List<LocationTurnover> withinFence(Long fenceId, Boolean enter);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.job;
import com.alibaba.fastjson.JSON;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yiring.app.design.strategy.rule.ScanAlarmContext;
import com.yiring.app.domain.location.LocationFence;
import com.yiring.app.domain.location.LocationFenceRepository;
import com.yiring.app.domain.location.LocationFenceRule;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import java.util.List;
import java.util.Set;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author tml
* @version 1.0
* @date 2022/5/14 10:10
*/
@Slf4j
@Component
public class FenceAlarmJob {
@Resource
private LocationFenceRepository locationFenceRepository;
@XxlJob("ScanAlarmHandler")
public void scanAlarmHandler() {
//查询出所有已启用的电子围栏信息
List<LocationFence> fenceList = locationFenceRepository.findAllByEnable(true);
for (LocationFence fence : fenceList) {
//获取该围栏下的所有报警规则
Set<LocationFenceRule> fenceRuleSet = fence.getRules();
for (LocationFenceRule fenceRule : fenceRuleSet) {
RuleParam ruleParam = JSON.parseObject(fenceRule.getRule(), RuleParam.class);
LocationFenceJobParam fenceJobParam = LocationFenceJobParam
.builder()
.rule(ruleParam)
.fenceId(fence.getId())
.alarmTypeId(fenceRule.getAlarmType().getId())
.tagSet(fence.getTags())
.mapId(fence.getMapId())
//todo 查询出正在报警的规则
//.oldAlarms()
.build();
LocationFenceJobVo locationFenceJobVo = ScanAlarmContext.scanAlarm(
fenceRule.getRelevanceParamType(),
fenceJobParam
);
//todo 将结果入库
}
}
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.param.location.fence;
import com.yiring.app.domain.location.LocationFenceAlarm;
import com.yiring.app.domain.location.LocationTag;
import com.yiring.app.param.location.rule.RuleParam;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 扫描围栏报警的param
* @author tml
* @version 1.0
* @date 2022/5/16 9:23
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LocationFenceJobParam implements Serializable {
@Serial
private static final long serialVersionUID = -1078898654919721759L;
/**
* 围栏的报警规则
*/
private RuleParam rule;
/**
* 围栏id
*/
private Long fenceId;
/**
* 报警类别id
*/
private Long alarmTypeId;
/**
* 围栏中的定位标签
*/
private Set<LocationTag> tagSet;
/**
* 围栏所属的地图id
*/
private Long mapId;
/**
* 属于该围栏当前正在报警的信息
*/
private List<LocationFenceAlarm> oldAlarms;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.util;
import com.yiring.common.constant.RegEx;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @author tml
* @version 1.0
* @date 2022/5/14 14:06
*/
public class TimeUtil {
/**
* 判断一个时间是否在配置的时间内
* @param time 判断的时间
* @param beginTime 配置的开始时间
* @param endTime 配置的结束时间
* @return true:在 false:不在
*/
public static boolean judgeTime(LocalDateTime time, String beginTime, String endTime) {
if (!beginTime.matches(RegEx.TIME_RULE) || !endTime.matches(RegEx.TIME_RULE)) {
throw new IllegalArgumentException("时间格式不正确");
}
DateTimeFormatter pattern = DateTimeFormatter.ofPattern("E HH:mm:ss");
String source = time.format(pattern);
int beginWeek = transform(beginTime.charAt(2));
int endWeek = transform(endTime.charAt(2));
int nowWeek = transform(source.charAt(1));
if (nowWeek < beginWeek || nowWeek > endWeek) {
return false;
}
int beginHour = Integer.parseInt(beginTime.substring(4, 6));
int endHour = Integer.parseInt(endTime.substring(4, 6));
int nowHour = Integer.parseInt(beginTime.substring(3, 5));
if (nowHour < beginHour || nowHour > endHour) {
return false;
}
int beginMinute = Integer.parseInt(beginTime.substring(7, 9));
int endMinute = Integer.parseInt(endTime.substring(7, 9));
int nowMinute = Integer.parseInt(beginTime.substring(6, 8));
if (nowMinute < beginMinute || nowHour > endMinute) {
return false;
}
int beginSecond = Integer.parseInt(beginTime.substring(10));
int endSecond = Integer.parseInt(endTime.substring(10));
int nowSecond = Integer.parseInt(beginTime.substring(9));
if (nowSecond < beginSecond || nowSecond > endSecond) {
return false;
}
return true;
}
private static int transform(char source) {
return switch (source) {
case '一' -> 1;
case '二' -> 2;
case '三' -> 3;
case '四' -> 4;
case '五' -> 5;
case '六' -> 6;
case '日' -> 7;
default -> 1;
};
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.vo.location.fence;
import com.yiring.app.domain.location.LocationFenceAlarm;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 扫描围栏报警的vo
* @author tml
* @version 1.0
* @date 2022/5/16 9:17
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LocationFenceJobVo implements Serializable {
@Serial
private static final long serialVersionUID = -594643836931827494L;
/**
* 需要添加的报警信息集合
*/
private List<LocationFenceAlarm> addAlarm;
/**
* 需要修改成取消报警的报警信息集合
*/
private List<LocationFenceAlarm> modifyAlarm;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.web.location.rule;
import com.yiring.app.design.check.rule.LocationFenceRuleContext;
import com.yiring.app.design.strategy.rule.LocationFenceRuleContext;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.LocationFenceRuleModifyParam;
import com.yiring.app.service.location.rule.impl.LocationFenceRuleServiceImpl;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论