Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
basic-api-boot
概览
概览
详情
活动
周期分析
版本库
存储库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Basic
basic-api-boot
Commits
6411c95b
提交
6411c95b
authored
5月 19, 2022
作者:
涂茂林
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat:围栏报警数据推送记录
上级
e54fde30
隐藏空白字符变更
内嵌
并排
正在显示
33 个修改的文件
包含
662 行增加
和
127 行删除
+662
-127
ReceiveStatusEnum.java
...java/com/yiring/app/constant/alarm/ReceiveStatusEnum.java
+58
-0
IScanAlarmStrategy.java
...va/com/yiring/app/design/strategy/IScanAlarmStrategy.java
+28
-0
AllowEntranceStrategy.java
...iring/app/design/strategy/rule/AllowEntranceStrategy.java
+3
-11
MaxPeopleNumberStrategy.java
...ing/app/design/strategy/rule/MaxPeopleNumberStrategy.java
+2
-11
MinPeopleNumberStrategy.java
...ing/app/design/strategy/rule/MinPeopleNumberStrategy.java
+5
-13
NotAllowLeaveStrategy.java
...iring/app/design/strategy/rule/NotAllowLeaveStrategy.java
+3
-11
RetentionDurationStrategy.java
...g/app/design/strategy/rule/RetentionDurationStrategy.java
+3
-12
StaticDurationStrategy.java
...ring/app/design/strategy/rule/StaticDurationStrategy.java
+3
-12
TriggerAlarmDistanceStrategy.java
...pp/design/strategy/rule/TriggerAlarmDistanceStrategy.java
+3
-12
FenceAlarmPushLog.java
...ava/com/yiring/app/domain/location/FenceAlarmPushLog.java
+57
-0
FenceAlarmPushLogRepository.java
...ring/app/domain/location/FenceAlarmPushLogRepository.java
+16
-0
LocationAlarmRule.java
...ava/com/yiring/app/domain/location/LocationAlarmRule.java
+17
-0
LocationAlarmRuleRepository.java
...ring/app/domain/location/LocationAlarmRuleRepository.java
+15
-1
LocationFenceAlarm.java
...va/com/yiring/app/domain/location/LocationFenceAlarm.java
+6
-2
FenceAlarmExcel.java
.../com/yiring/app/excel/location/fence/FenceAlarmExcel.java
+18
-12
FenceAlarmJob.java
app/src/main/java/com/yiring/app/job/FenceAlarmJob.java
+49
-0
FenceAlarmConditionParam.java
...ng/app/param/location/fence/FenceAlarmConditionParam.java
+2
-2
FenceAlarmPushLogConditionParam.java
...param/location/fence/FenceAlarmPushLogConditionParam.java
+40
-0
LocationFenceJobParam.java
...iring/app/param/location/fence/LocationFenceJobParam.java
+5
-0
HistoryRouteService.java
...ing/app/service/analysis/history/HistoryRouteService.java
+10
-0
HistoryRouteServiceImpl.java
...ervice/analysis/history/impl/HistoryRouteServiceImpl.java
+23
-0
FenceAlarmPushLogService.java
.../app/service/location/fence/FenceAlarmPushLogService.java
+27
-0
FenceAlarmService.java
.../yiring/app/service/location/fence/FenceAlarmService.java
+8
-0
FenceAlarmPushLogServiceImpl.java
...ice/location/fence/impl/FenceAlarmPushLogServiceImpl.java
+76
-0
FenceAlarmServiceImpl.java
...pp/service/location/fence/impl/FenceAlarmServiceImpl.java
+27
-2
TimeUtil.java
app/src/main/java/com/yiring/app/util/TimeUtil.java
+20
-22
FenceAlarmPushLogVo.java
...com/yiring/app/vo/location/fence/FenceAlarmPushLogVo.java
+57
-0
FenceAlarmVo.java
...n/java/com/yiring/app/vo/location/fence/FenceAlarmVo.java
+19
-2
AlarmTypeController.java
...in/java/com/yiring/app/web/alarm/AlarmTypeController.java
+10
-0
HistoryRouteController.java
...ring/app/web/analysis/history/HistoryRouteController.java
+11
-0
FenceAlarmPushLogController.java
...g/app/web/location/fence/FenceAlarmPushLogController.java
+39
-0
LocationAlarmRuleController.java
...ng/app/web/location/rule/LocationAlarmRuleController.java
+1
-1
LocationFenceRuleController.java
...ng/app/web/location/rule/LocationFenceRuleController.java
+1
-1
没有找到文件。
app/src/main/java/com/yiring/app/constant/alarm/ReceiveStatusEnum.java
0 → 100644
浏览文件 @
6411c95b
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
constant
.
alarm
;
import
com.yiring.app.vo.CodeNameVo
;
import
java.util.ArrayList
;
import
java.util.List
;
import
lombok.Getter
;
/**
* 接受状态枚举
* @author tml
* @version 1.0
* @date 2022/5/18 9:37
*/
public
enum
ReceiveStatusEnum
{
/**
* 成功
*/
SUCCESS
(
1
,
"成功"
),
/**
* 失败
*/
FAIL
(
2
,
"失败"
);
private
static
final
List
<
CodeNameVo
>
LIST
;
static
{
LIST
=
new
ArrayList
<>();
for
(
ReceiveStatusEnum
item
:
values
())
{
LIST
.
add
(
new
CodeNameVo
(
item
.
getCode
(),
item
.
name
));
}
}
@Getter
private
final
int
code
;
@Getter
private
final
String
name
;
ReceiveStatusEnum
(
Integer
code
,
String
name
)
{
this
.
code
=
code
;
this
.
name
=
name
;
}
public
static
String
getByCode
(
int
code
)
{
for
(
ReceiveStatusEnum
item
:
values
())
{
if
(
item
.
code
==
code
)
{
return
item
.
getName
();
}
}
return
"未知状态"
;
}
public
static
List
<
CodeNameVo
>
findAll
()
{
return
LIST
;
}
}
app/src/main/java/com/yiring/app/design/strategy/IScanAlarmStrategy.java
浏览文件 @
6411c95b
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
design
.
strategy
;
import
com.yiring.app.domain.location.LocationFenceAlarm
;
import
com.yiring.app.param.location.fence.LocationFenceJobParam
;
import
com.yiring.app.vo.location.fence.LocationFenceJobVo
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
org.springframework.util.CollectionUtils
;
/**
* 扫描是否满足报警策略
...
...
@@ -18,4 +23,27 @@ public interface IScanAlarmStrategy {
* @return 需要报警的报警信息
*/
LocationFenceJobVo
scanAlarm
(
LocationFenceJobParam
param
);
/**
* 将两个集合不相交的部分筛选出来,并封装到结果集
* @param newAlarms 集合1
* @param oldAlarms 集合2
* @param jobVo 结果集
*/
static
void
notIntersect
(
List
<
LocationFenceAlarm
>
newAlarms
,
List
<
LocationFenceAlarm
>
oldAlarms
,
LocationFenceJobVo
jobVo
)
{
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
);
}
}
app/src/main/java/com/yiring/app/design/strategy/rule/AllowEntranceStrategy.java
浏览文件 @
6411c95b
...
...
@@ -37,6 +37,7 @@ public class AllowEntranceStrategy implements IParamInitStrategy<LocationFenceRu
public
AllowEntranceStrategy
()
{
Integer
relevanceParam
=
RelevanceParamEnum
.
ALLOW_ENTRANCE
.
getCode
();
LocationFenceRuleContext
.
register
(
relevanceParam
,
this
);
ScanAlarmContext
.
register
(
relevanceParam
,
this
);
}
@Override
...
...
@@ -90,7 +91,7 @@ public class AllowEntranceStrategy implements IParamInitStrategy<LocationFenceRu
.
stream
()
.
filter
(
e
->
!
uuids
.
contains
(
e
.
getUser
().
getUuid
()))
.
map
(
e
->
{
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
build
();
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
name
(
param
.
getFenceName
()).
build
();
AlarmType
alarmType
=
AlarmType
.
builder
().
id
(
alarmTypeId
).
build
();
return
LocationFenceAlarm
.
builder
()
...
...
@@ -106,16 +107,7 @@ public class AllowEntranceStrategy implements IParamInitStrategy<LocationFenceRu
})
.
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
);
IScanAlarmStrategy
.
notIntersect
(
newAlarms
,
oldAlarms
,
jobVo
);
return
jobVo
;
}
}
app/src/main/java/com/yiring/app/design/strategy/rule/MaxPeopleNumberStrategy.java
浏览文件 @
6411c95b
...
...
@@ -107,7 +107,7 @@ public class MaxPeopleNumberStrategy implements IParamInitStrategy<LocationFence
//记录触发报警的信息(例如最大人数是3,那么前三个员工进入的不会记录)
for
(
int
i
=
0
;
i
<
exceed
;
i
++)
{
LocationTurnover
turnover
=
turnoverList
.
get
(
i
);
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
build
();
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
name
(
param
.
getFenceName
()).
build
();
AlarmType
alarmType
=
AlarmType
.
builder
().
id
(
alarmTypeId
).
build
();
LocationFenceAlarm
locationFenceAlarm
=
LocationFenceAlarm
.
builder
()
...
...
@@ -123,16 +123,7 @@ public class MaxPeopleNumberStrategy implements IParamInitStrategy<LocationFence
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
);
IScanAlarmStrategy
.
notIntersect
(
newAlarms
,
oldAlarms
,
jobVo
);
return
jobVo
;
}
}
app/src/main/java/com/yiring/app/design/strategy/rule/MinPeopleNumberStrategy.java
浏览文件 @
6411c95b
...
...
@@ -40,6 +40,7 @@ public class MinPeopleNumberStrategy implements IParamInitStrategy<LocationFence
public
MinPeopleNumberStrategy
()
{
Integer
relevanceParam
=
RelevanceParamEnum
.
MIN_PEOPLE_NUMBER
.
getCode
();
LocationFenceRuleContext
.
register
(
relevanceParam
,
this
);
ScanAlarmContext
.
register
(
relevanceParam
,
this
);
}
@Override
...
...
@@ -92,11 +93,11 @@ public class MinPeopleNumberStrategy implements IParamInitStrategy<LocationFence
//少的人数
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
()
...
...
@@ -106,7 +107,7 @@ public class MinPeopleNumberStrategy implements IParamInitStrategy<LocationFence
//记录触发报警的信息(例如最小人数是3,这段时间一开始有6个人在围栏,然后出去的4个,那么只有第四个人出去才会记录)
for
(
int
i
=
0
;
i
<
missing
;
i
++)
{
LocationTurnover
turnover
=
turnoverList
.
get
(
i
);
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
build
();
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
name
(
param
.
getFenceName
()).
build
();
AlarmType
alarmType
=
AlarmType
.
builder
().
id
(
alarmTypeId
).
build
();
LocationFenceAlarm
locationFenceAlarm
=
LocationFenceAlarm
.
builder
()
...
...
@@ -122,16 +123,7 @@ public class MinPeopleNumberStrategy implements IParamInitStrategy<LocationFence
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
);
IScanAlarmStrategy
.
notIntersect
(
newAlarms
,
oldAlarms
,
jobVo
);
return
jobVo
;
}
}
app/src/main/java/com/yiring/app/design/strategy/rule/NotAllowLeaveStrategy.java
浏览文件 @
6411c95b
...
...
@@ -40,6 +40,7 @@ public class NotAllowLeaveStrategy implements IParamInitStrategy<LocationFenceRu
public
NotAllowLeaveStrategy
()
{
Integer
relevanceParam
=
RelevanceParamEnum
.
NOT_ALLOW_LEAVE
.
getCode
();
LocationFenceRuleContext
.
register
(
relevanceParam
,
this
);
ScanAlarmContext
.
register
(
relevanceParam
,
this
);
}
@Override
...
...
@@ -104,7 +105,7 @@ public class NotAllowLeaveStrategy implements IParamInitStrategy<LocationFenceRu
.
stream
()
.
filter
(
e
->
uuids
.
contains
(
e
.
getTag
().
getUser
().
getUuid
()))
.
map
(
e
->
{
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
build
();
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
name
(
param
.
getFenceName
()).
build
();
AlarmType
alarmType
=
AlarmType
.
builder
().
id
(
alarmTypeId
).
build
();
return
LocationFenceAlarm
.
builder
()
...
...
@@ -120,16 +121,7 @@ public class NotAllowLeaveStrategy implements IParamInitStrategy<LocationFenceRu
})
.
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
);
IScanAlarmStrategy
.
notIntersect
(
newAlarms
,
oldAlarms
,
jobVo
);
return
jobVo
;
}
}
app/src/main/java/com/yiring/app/design/strategy/rule/RetentionDurationStrategy.java
浏览文件 @
6411c95b
...
...
@@ -19,7 +19,6 @@ import java.util.Set;
import
java.util.stream.Collectors
;
import
javax.annotation.Resource
;
import
org.springframework.stereotype.Component
;
import
org.springframework.util.CollectionUtils
;
/**
* 滞留时长相关策略
...
...
@@ -36,6 +35,7 @@ public class RetentionDurationStrategy implements IParamInitStrategy<LocationFen
public
RetentionDurationStrategy
()
{
Integer
relevanceParam
=
RelevanceParamEnum
.
RETENTION_DURATION
.
getCode
();
LocationFenceRuleContext
.
register
(
relevanceParam
,
this
);
ScanAlarmContext
.
register
(
relevanceParam
,
this
);
}
@Override
...
...
@@ -67,7 +67,7 @@ public class RetentionDurationStrategy implements IParamInitStrategy<LocationFen
.
stream
()
.
filter
(
e
->
e
.
getTime
().
isBefore
(
time
))
.
map
(
e
->
{
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
build
();
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
name
(
param
.
getFenceName
()).
build
();
AlarmType
alarmType
=
AlarmType
.
builder
().
id
(
alarmTypeId
).
build
();
return
LocationFenceAlarm
.
builder
()
...
...
@@ -83,16 +83,7 @@ public class RetentionDurationStrategy implements IParamInitStrategy<LocationFen
})
.
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
);
IScanAlarmStrategy
.
notIntersect
(
newAlarms
,
oldAlarms
,
jobVo
);
return
jobVo
;
}
}
app/src/main/java/com/yiring/app/design/strategy/rule/StaticDurationStrategy.java
浏览文件 @
6411c95b
...
...
@@ -20,7 +20,6 @@ import java.util.List;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
org.springframework.stereotype.Component
;
import
org.springframework.util.CollectionUtils
;
/**
* 静止时长相关策略
...
...
@@ -34,6 +33,7 @@ public class StaticDurationStrategy implements IParamInitStrategy<LocationFenceR
public
StaticDurationStrategy
()
{
Integer
relevanceParam
=
RelevanceParamEnum
.
STATIC_DURATION
.
getCode
();
LocationFenceRuleContext
.
register
(
relevanceParam
,
this
);
ScanAlarmContext
.
register
(
relevanceParam
,
this
);
}
@Override
...
...
@@ -65,7 +65,7 @@ public class StaticDurationStrategy implements IParamInitStrategy<LocationFenceR
.
filter
(
LocationTag:
:
getSilent
)
.
filter
(
e
->
e
.
getTime
().
isBefore
(
time
))
.
map
(
e
->
{
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
build
();
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
name
(
param
.
getFenceName
()).
build
();
AlarmType
alarmType
=
AlarmType
.
builder
().
id
(
alarmTypeId
).
build
();
return
LocationFenceAlarm
.
builder
()
...
...
@@ -81,16 +81,7 @@ public class StaticDurationStrategy implements IParamInitStrategy<LocationFenceR
})
.
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
);
IScanAlarmStrategy
.
notIntersect
(
newAlarms
,
oldAlarms
,
jobVo
);
return
jobVo
;
}
}
app/src/main/java/com/yiring/app/design/strategy/rule/TriggerAlarmDistanceStrategy.java
浏览文件 @
6411c95b
...
...
@@ -23,7 +23,6 @@ import java.util.stream.Collectors;
import
javax.annotation.Resource
;
import
org.locationtech.jts.geom.Geometry
;
import
org.springframework.stereotype.Component
;
import
org.springframework.util.CollectionUtils
;
/**
* 触发报警距离相关策略
...
...
@@ -40,6 +39,7 @@ public class TriggerAlarmDistanceStrategy implements IParamInitStrategy<Location
public
TriggerAlarmDistanceStrategy
()
{
Integer
relevanceParam
=
RelevanceParamEnum
.
TRIGGER_ALARM_DISTANCE
.
getCode
();
LocationFenceRuleContext
.
register
(
relevanceParam
,
this
);
ScanAlarmContext
.
register
(
relevanceParam
,
this
);
}
@Override
...
...
@@ -70,7 +70,7 @@ public class TriggerAlarmDistanceStrategy implements IParamInitStrategy<Location
List
<
LocationFenceAlarm
>
newAlarms
=
locationTags
.
stream
()
.
map
(
e
->
{
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
build
();
LocationFence
fence
=
LocationFence
.
builder
().
id
(
fenceId
).
name
(
param
.
getFenceName
()).
build
();
AlarmType
alarmType
=
AlarmType
.
builder
().
id
(
alarmTypeId
).
build
();
return
LocationFenceAlarm
.
builder
()
...
...
@@ -86,16 +86,7 @@ public class TriggerAlarmDistanceStrategy implements IParamInitStrategy<Location
})
.
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
);
IScanAlarmStrategy
.
notIntersect
(
newAlarms
,
oldAlarms
,
jobVo
);
return
jobVo
;
}
}
app/src/main/java/com/yiring/app/domain/location/FenceAlarmPushLog.java
0 → 100644
浏览文件 @
6411c95b
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
domain
.
location
;
import
com.fasterxml.jackson.annotation.JsonIgnore
;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.common.domain.BasicEntity
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.time.LocalDateTime
;
import
javax.persistence.Entity
;
import
javax.persistence.JoinColumn
;
import
javax.persistence.ManyToOne
;
import
javax.persistence.Table
;
import
lombok.*
;
import
lombok.experimental.FieldNameConstants
;
import
org.hibernate.annotations.Comment
;
/**
* @author tml
* @version 1.0
* @date 2022/5/18 9:25
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@FieldNameConstants
@Entity
@Table
(
name
=
"BS_FENCE_ALARM_PUSH_LOG"
)
@Comment
(
"围栏报警推送记录"
)
public
class
FenceAlarmPushLog
extends
BasicEntity
implements
Serializable
{
@Serial
private
static
final
long
serialVersionUID
=
7859768330784835564L
;
@ManyToOne
@JoinColumn
(
name
=
"fence_alarm_id"
)
@JsonIgnore
@Comment
(
"围栏报警记录"
)
private
LocationFenceAlarm
fenceAlarm
;
@Comment
(
"通知方式"
)
private
Integer
informManner
;
@Comment
(
"接收状态"
)
private
Integer
status
;
@Comment
(
"接收时间"
)
private
LocalDateTime
time
;
@ManyToOne
@JoinColumn
(
name
=
"user_id"
)
@JsonIgnore
@Comment
(
"报警接收人"
)
User
user
;
}
app/src/main/java/com/yiring/app/domain/location/FenceAlarmPushLogRepository.java
0 → 100644
浏览文件 @
6411c95b
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
domain
.
location
;
import
java.io.Serializable
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
org.springframework.data.jpa.repository.JpaSpecificationExecutor
;
import
org.springframework.stereotype.Repository
;
/**
* @author tml
* @version 1.0
* @date 2022/5/18 10:29
*/
@Repository
public
interface
FenceAlarmPushLogRepository
extends
JpaRepository
<
FenceAlarmPushLog
,
Serializable
>,
JpaSpecificationExecutor
<
FenceAlarmPushLog
>
{}
app/src/main/java/com/yiring/app/domain/location/LocationAlarmRule.java
浏览文件 @
6411c95b
...
...
@@ -13,6 +13,7 @@ import lombok.experimental.FieldNameConstants;
import
lombok.experimental.SuperBuilder
;
import
org.hibernate.annotations.Comment
;
import
org.hibernate.annotations.Where
;
import
org.springframework.util.CollectionUtils
;
/**
* @author tml
...
...
@@ -62,4 +63,20 @@ public class LocationAlarmRule extends BasicEntity implements Serializable {
@Comment
(
value
=
"是否删除"
)
@Column
(
nullable
=
false
)
Boolean
deleted
;
/**
* 判断本实体类的报警类型集是否包含搞报警类型
* @param alarmType 报警类型
* @return true:包含 false:不包含
*/
public
boolean
typesContains
(
AlarmType
alarmType
)
{
if
(!
CollectionUtils
.
isEmpty
(
alarmTypes
))
{
for
(
AlarmType
item
:
alarmTypes
)
{
if
(
item
.
getId
().
equals
(
alarmType
.
getId
()))
{
return
true
;
}
}
}
return
false
;
}
}
app/src/main/java/com/yiring/app/domain/location/LocationAlarmRuleRepository.java
浏览文件 @
6411c95b
...
...
@@ -2,8 +2,11 @@
package
com
.
yiring
.
app
.
domain
.
location
;
import
java.io.Serializable
;
import
java.util.Collection
;
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
;
/**
...
...
@@ -13,4 +16,15 @@ import org.springframework.stereotype.Repository;
*/
@Repository
public
interface
LocationAlarmRuleRepository
extends
JpaRepository
<
LocationAlarmRule
,
Serializable
>,
JpaSpecificationExecutor
<
LocationAlarmRule
>
{}
extends
JpaRepository
<
LocationAlarmRule
,
Serializable
>,
JpaSpecificationExecutor
<
LocationAlarmRule
>
{
/**
* 根据多个围栏id查询
* @param fenceIds 围栏id
* @return 规则
*/
@Query
(
value
=
"SELECT * FROM BS_LOCATION_ALARM_RULE WHERE deleted = false AND fence_id IN (?1)"
,
nativeQuery
=
true
)
List
<
LocationAlarmRule
>
findAllByFenceIds
(
Collection
<
Long
>
fenceIds
);
}
app/src/main/java/com/yiring/app/domain/location/LocationFenceAlarm.java
浏览文件 @
6411c95b
...
...
@@ -7,6 +7,8 @@ import com.yiring.common.domain.BasicEntity;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.time.LocalDateTime
;
import
java.util.ArrayList
;
import
java.util.List
;
import
javax.persistence.*
;
import
lombok.*
;
import
lombok.experimental.FieldDefaults
;
...
...
@@ -71,8 +73,10 @@ public class LocationFenceAlarm extends BasicEntity implements Serializable {
@Enumerated
(
EnumType
.
STRING
)
Status
status
;
// 推送记录集合(含接收状态)
// TODO
@Builder
.
Default
@OneToMany
(
mappedBy
=
"fenceAlarm"
)
@Comment
(
"推送记录"
)
List
<
FenceAlarmPushLog
>
pushLogs
=
new
ArrayList
<>();
@SuppressWarnings
({
"unused"
})
public
enum
Status
{
...
...
app/src/main/java/com/yiring/app/excel/location/fence/FenceAlarmExcel.java
浏览文件 @
6411c95b
...
...
@@ -8,6 +8,7 @@ import com.yiring.app.domain.location.LocationFenceAlarm;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.time.LocalDateTime
;
import
java.util.stream.Collectors
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
...
...
@@ -28,37 +29,43 @@ public class FenceAlarmExcel implements Serializable {
@Serial
private
static
final
long
serialVersionUID
=
4526095986813965381L
;
@ExcelColumn
(
title
=
"地图名称"
)
@ExcelColumn
(
title
=
"地图名称"
,
width
=
10
)
private
String
mapName
;
@ExcelColumn
(
title
=
"围栏名称"
)
@ExcelColumn
(
title
=
"围栏名称"
,
width
=
10
)
private
String
fenceName
;
@ExcelColumn
(
title
=
"围栏类别"
)
@ExcelColumn
(
title
=
"围栏类别"
,
width
=
10
)
private
String
fenceTypeName
;
@ExcelColumn
(
title
=
"报警人员"
)
@ExcelColumn
(
title
=
"报警人员"
,
width
=
10
)
private
String
realName
;
@ExcelColumn
(
title
=
"标签号"
)
@ExcelColumn
(
title
=
"标签号"
,
width
=
10
)
private
String
tagId
;
@ExcelColumn
(
title
=
"报警开始时间"
)
@ExcelColumn
(
title
=
"报警开始时间"
,
width
=
15
)
private
LocalDateTime
startTime
;
@ExcelColumn
(
title
=
"报警结束时间"
)
@ExcelColumn
(
title
=
"报警结束时间"
,
width
=
15
)
private
LocalDateTime
endTime
;
@ExcelColumn
(
title
=
"报警类型"
)
@ExcelColumn
(
title
=
"报警类型"
,
width
=
10
)
private
String
alarmTypeName
;
@ExcelColumn
(
title
=
"接收人"
)
@ExcelColumn
(
title
=
"接收人"
,
width
=
15
)
private
String
recipient
;
@ExcelColumn
(
title
=
"报警状态"
)
@ExcelColumn
(
title
=
"报警状态"
,
width
=
10
)
private
String
statusName
;
public
static
FenceAlarmExcel
transform
(
LocationFenceAlarm
fenceAlarm
)
{
String
recipient
=
fenceAlarm
.
getPushLogs
()
.
stream
()
.
map
(
e
->
e
.
getUser
().
getRealName
())
.
distinct
()
.
collect
(
Collectors
.
joining
(
", "
));
return
FenceAlarmExcel
.
builder
()
.
fenceName
(
fenceAlarm
.
getFence
().
getName
())
...
...
@@ -68,8 +75,7 @@ public class FenceAlarmExcel implements Serializable {
.
startTime
(
fenceAlarm
.
getStartTime
())
.
endTime
(
fenceAlarm
.
getEndTime
())
.
alarmTypeName
(
fenceAlarm
.
getType
().
getName
())
//todo
//.recipient()
.
recipient
(
recipient
)
.
statusName
(
fenceAlarm
.
getStatus
().
text
())
.
build
();
}
...
...
app/src/main/java/com/yiring/app/job/FenceAlarmJob.java
浏览文件 @
6411c95b
...
...
@@ -2,12 +2,15 @@
package
com
.
yiring
.
app
.
job
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONArray
;
import
com.xxl.job.core.handler.annotation.XxlJob
;
import
com.yiring.app.design.strategy.rule.ScanAlarmContext
;
import
com.yiring.app.domain.location.*
;
import
com.yiring.app.param.location.fence.LocationFenceJobParam
;
import
com.yiring.app.param.location.rule.RuleParam
;
import
com.yiring.app.service.location.fence.FenceAlarmService
;
import
com.yiring.app.vo.location.fence.LocationFenceJobVo
;
import
com.yiring.auth.domain.user.User
;
import
java.time.LocalDateTime
;
import
java.util.ArrayList
;
import
java.util.List
;
...
...
@@ -34,6 +37,15 @@ public class FenceAlarmJob {
@Resource
private
LocationFenceAlarmRepository
locationFenceAlarmRepository
;
@Resource
private
LocationAlarmRuleRepository
locationAlarmRuleRepository
;
@Resource
private
FenceAlarmPushLogRepository
fenceAlarmPushLogRepository
;
@Resource
private
FenceAlarmService
fenceAlarmService
;
@XxlJob
(
"ScanAlarmHandler"
)
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
scanAlarmHandler
()
{
...
...
@@ -60,6 +72,7 @@ public class FenceAlarmJob {
.
builder
()
.
rule
(
ruleParam
)
.
fenceId
(
fence
.
getId
())
.
fenceName
(
fence
.
getName
())
.
alarmTypeId
(
fenceRule
.
getAlarmType
().
getId
())
.
tagSet
(
fence
.
getTags
())
.
mapId
(
fence
.
getMapId
())
...
...
@@ -73,6 +86,8 @@ public class FenceAlarmJob {
jobVo
.
merge
(
locationFenceJobVo
);
}
}
//异步将新添加的报警信息推送给前端
fenceAlarmService
.
alarmPushWeb
(
jobVo
.
getAddAlarm
());
//添加报警和关闭报警
locationFenceAlarmRepository
.
saveAllAndFlush
(
jobVo
.
getAddAlarm
());
List
<
Long
>
ids
=
jobVo
.
getModifyAlarm
().
stream
().
map
(
LocationFenceAlarm:
:
getId
).
collect
(
Collectors
.
toList
());
...
...
@@ -82,5 +97,39 @@ public class FenceAlarmJob {
JSON
.
toJSONString
(
jobVo
.
getAddAlarm
()),
JSON
.
toJSONString
(
jobVo
.
getModifyAlarm
())
);
//todo 推送报警信息
//添加报警推送记录,可以考虑异步执行
Set
<
Long
>
fenceIds
=
jobVo
.
getAddAlarm
().
stream
().
map
(
e
->
e
.
getFence
().
getId
()).
collect
(
Collectors
.
toSet
());
List
<
LocationAlarmRule
>
locationAlarmRuleList
=
locationAlarmRuleRepository
.
findAllByFenceIds
(
fenceIds
);
List
<
FenceAlarmPushLog
>
pushLogList
=
new
ArrayList
<>();
for
(
LocationFenceAlarm
fenceAlarm
:
jobVo
.
getAddAlarm
())
{
//筛选出该条报警记录对应的报警规则
locationAlarmRuleList
=
locationAlarmRuleList
.
stream
()
.
filter
(
e
->
fenceAlarm
.
getFence
().
getId
().
equals
(
e
.
getLocationFence
().
getId
()))
.
filter
(
e
->
e
.
typesContains
(
fenceAlarm
.
getType
()))
.
collect
(
Collectors
.
toList
());
//一条报警记录可能对应多个报警规则(报警给谁的规则),报警规则的接收人和通知方式用笛卡尔积存到数据库
for
(
LocationAlarmRule
alarmRule
:
locationAlarmRuleList
)
{
List
<
Integer
>
informManners
=
JSONArray
.
parseArray
(
alarmRule
.
getInformManner
(),
Integer
.
class
);
for
(
User
user
:
alarmRule
.
getUsers
())
{
for
(
Integer
informManner
:
informManners
)
{
FenceAlarmPushLog
pushLog
=
FenceAlarmPushLog
.
builder
()
.
fenceAlarm
(
fenceAlarm
)
.
informManner
(
informManner
)
.
user
(
user
)
.
build
();
pushLogList
.
add
(
pushLog
);
}
}
}
}
//落库
fenceAlarmPushLogRepository
.
saveAllAndFlush
(
pushLogList
);
log
.
info
(
"FenceAlarmJob.scanAlarmHandler: 生成的推送记录:[{}]"
,
JSON
.
toJSONString
(
pushLogList
));
}
}
app/src/main/java/com/yiring/app/param/location/fence/FenceAlarmConditionParam.java
浏览文件 @
6411c95b
...
...
@@ -35,12 +35,12 @@ public class FenceAlarmConditionParam implements Serializable {
@ApiModelProperty
(
value
=
"报警人员真名"
,
example
=
"张三"
)
private
String
realName
;
@ApiModelProperty
(
value
=
"报警状态"
,
example
=
"true
|false
"
)
@ApiModelProperty
(
value
=
"报警状态"
,
example
=
"true"
)
private
Boolean
status
;
@ApiModelProperty
(
value
=
"报警开始时间"
,
example
=
"2022-05-06 14:00:00"
)
private
LocalDateTime
beginTime
;
@ApiModelProperty
(
value
=
"报警结束时间"
,
example
=
"2022-05-7 14:00:00"
)
@ApiModelProperty
(
value
=
"报警结束时间"
,
example
=
"2022-05-
0
7 14:00:00"
)
private
LocalDateTime
endTime
;
}
app/src/main/java/com/yiring/app/param/location/fence/FenceAlarmPushLogConditionParam.java
0 → 100644
浏览文件 @
6411c95b
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
param
.
location
.
fence
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModelProperty
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.util.Set
;
import
javax.validation.constraints.NotNull
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* @author tml
* @version 1.0
* @date 2022/5/18 10:08
*/
@ApiModel
(
"围栏报警推送记录"
)
@Data
@AllArgsConstructor
@NoArgsConstructor
public
class
FenceAlarmPushLogConditionParam
implements
Serializable
{
@Serial
private
static
final
long
serialVersionUID
=
-
3348481008334535142L
;
@ApiModelProperty
(
value
=
"围栏报警记录id"
,
example
=
"1"
)
@NotNull
(
message
=
"围栏报警记录id不能为空"
)
private
Long
fenceAlarmId
;
@ApiModelProperty
(
value
=
"通知方式: 1-app消息 2-短信通知 3-电话通知"
,
example
=
"[1,2,3]"
,
dataType
=
"array"
)
private
Set
<
Integer
>
informManner
;
@ApiModelProperty
(
value
=
"接受状态: 1-成功 2-失败"
,
example
=
"1"
)
private
Integer
status
;
@ApiModelProperty
(
value
=
"联系电话"
,
example
=
"18283943672"
)
private
String
phone
;
}
app/src/main/java/com/yiring/app/param/location/fence/LocationFenceJobParam.java
浏览文件 @
6411c95b
...
...
@@ -40,6 +40,11 @@ public class LocationFenceJobParam implements Serializable {
private
Long
fenceId
;
/**
* 围栏名称
*/
private
String
fenceName
;
/**
* 报警类别id
*/
private
Long
alarmTypeId
;
...
...
app/src/main/java/com/yiring/app/service/analysis/history/HistoryRouteService.java
浏览文件 @
6411c95b
...
...
@@ -4,8 +4,10 @@ package com.yiring.app.service.analysis.history;
import
com.yiring.app.param.analysis.history.HistoryRouteConditionParam
;
import
com.yiring.app.vo.analysis.history.HistoryRouteVo
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.param.PageParam
;
import
com.yiring.common.vo.PageVo
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.validation.Valid
;
/**
* @author tml
...
...
@@ -21,6 +23,14 @@ public interface HistoryRouteService {
Result
<
PageVo
<
HistoryRouteVo
>>
findByCondition
(
HistoryRouteConditionParam
param
);
/**
* 分页条件查询
* @param param 条件
* @param pageParam 分页参数
* @return 历史轨迹信息
*/
Result
<
PageVo
<
HistoryRouteVo
>>
findByPage
(
@Valid
HistoryRouteConditionParam
param
,
@Valid
PageParam
pageParam
);
/**
* 导出历史轨迹信息
* @param param 地图、员工和时间条件
* @param response 历史轨迹信息
...
...
app/src/main/java/com/yiring/app/service/analysis/history/impl/HistoryRouteServiceImpl.java
浏览文件 @
6411c95b
...
...
@@ -12,6 +12,7 @@ import com.yiring.app.vo.analysis.history.HistoryRouteVo;
import
com.yiring.app.vo.map.MapVo
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.core.Status
;
import
com.yiring.common.param.PageParam
;
import
com.yiring.common.vo.PageVo
;
import
java.io.OutputStream
;
import
java.net.URLEncoder
;
...
...
@@ -25,6 +26,7 @@ import javax.persistence.criteria.Predicate;
import
javax.servlet.http.HttpServletResponse
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.poi.ss.usermodel.Workbook
;
import
org.springframework.data.domain.Pageable
;
import
org.springframework.data.jpa.domain.Specification
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
...
...
@@ -63,6 +65,27 @@ public class HistoryRouteServiceImpl implements HistoryRouteService {
}
@Override
public
Result
<
PageVo
<
HistoryRouteVo
>>
findByPage
(
HistoryRouteConditionParam
param
,
PageParam
pageParam
)
{
Pageable
pageable
=
PageParam
.
toPageable
(
pageParam
);
Specification
<
LocationLog
>
specification
=
getSpecification
(
param
);
ArrayList
<
MapVo
.
MapVoReuslt
>
list1
=
new
ArrayList
<>();
List
<
LocationLog
>
list
=
locationLogRepository
.
findAll
(
specification
,
pageable
)
.
stream
()
.
collect
(
Collectors
.
toList
());
List
<
HistoryRouteVo
>
voList
=
list
.
stream
()
.
map
(
e
->
{
HistoryRouteVo
routeVo
=
HistoryRouteVo
.
transform
(
e
);
routeVo
.
setMapName
(
mapUtil
.
getMapName
(
e
.
getAreaId
().
intValue
()));
return
routeVo
;
})
.
collect
(
Collectors
.
toList
());
PageVo
<
HistoryRouteVo
>
pageVo
=
PageVo
.
build
(
voList
,
voList
.
size
());
return
Result
.
ok
(
pageVo
);
}
@Override
public
void
exportHistoryRoute
(
HistoryRouteConditionParam
param
,
HttpServletResponse
response
)
{
Result
<
PageVo
<
HistoryRouteVo
>>
result
=
findByCondition
(
param
);
if
(
Status
.
OK
.
value
()
!=
result
.
getStatus
())
{
...
...
app/src/main/java/com/yiring/app/service/location/fence/FenceAlarmPushLogService.java
0 → 100644
浏览文件 @
6411c95b
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
service
.
location
.
fence
;
import
com.yiring.app.param.location.fence.FenceAlarmPushLogConditionParam
;
import
com.yiring.app.vo.location.fence.FenceAlarmPushLogVo
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.param.PageParam
;
import
com.yiring.common.vo.PageVo
;
import
javax.validation.Valid
;
/**
* @author tml
* @version 1.0
* @date 2022/5/18 10:26
*/
public
interface
FenceAlarmPushLogService
{
/**
* 查询围栏报警推送记录列表
* @param conditionParam 条件参数
* @param pageParam 分页参数
* @return 推送记录
*/
Result
<
PageVo
<
FenceAlarmPushLogVo
>>
findList
(
@Valid
FenceAlarmPushLogConditionParam
conditionParam
,
@Valid
PageParam
pageParam
);
}
app/src/main/java/com/yiring/app/service/location/fence/FenceAlarmService.java
浏览文件 @
6411c95b
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
service
.
location
.
fence
;
import
com.yiring.app.domain.location.LocationFenceAlarm
;
import
com.yiring.app.param.location.fence.FenceAlarmConditionParam
;
import
com.yiring.app.vo.IdNameVo
;
import
com.yiring.app.vo.location.fence.FenceAlarmVo
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.param.PageParam
;
import
com.yiring.common.vo.PageVo
;
import
java.util.List
;
import
javax.servlet.http.HttpServletResponse
;
/**
...
...
@@ -34,4 +36,10 @@ public interface FenceAlarmService {
* @param param 查询条件
*/
void
export
(
FenceAlarmConditionParam
param
,
HttpServletResponse
response
);
/**
* 推送报警信息给前端
* @param newAlarm 新生成的报警信息
*/
void
alarmPushWeb
(
List
<
LocationFenceAlarm
>
newAlarm
);
}
app/src/main/java/com/yiring/app/service/location/fence/impl/FenceAlarmPushLogServiceImpl.java
0 → 100644
浏览文件 @
6411c95b
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
service
.
location
.
fence
.
impl
;
import
com.yiring.app.domain.location.FenceAlarmPushLog
;
import
com.yiring.app.domain.location.FenceAlarmPushLogRepository
;
import
com.yiring.app.param.location.fence.FenceAlarmPushLogConditionParam
;
import
com.yiring.app.service.location.fence.FenceAlarmPushLogService
;
import
com.yiring.app.vo.location.fence.FenceAlarmPushLogVo
;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.param.PageParam
;
import
com.yiring.common.vo.PageVo
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.stream.Collectors
;
import
javax.annotation.Resource
;
import
javax.persistence.criteria.*
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.data.domain.Page
;
import
org.springframework.data.domain.Pageable
;
import
org.springframework.data.jpa.domain.Specification
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
/**
* @author tml
* @version 1.0
* @date 2022/5/18 10:27
*/
@Slf4j
@Service
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
class
FenceAlarmPushLogServiceImpl
implements
FenceAlarmPushLogService
{
@Resource
private
FenceAlarmPushLogRepository
fenceAlarmPushLogRepository
;
@Override
public
Result
<
PageVo
<
FenceAlarmPushLogVo
>>
findList
(
FenceAlarmPushLogConditionParam
conditionParam
,
PageParam
pageParam
)
{
Pageable
pageable
=
PageParam
.
toPageable
(
pageParam
);
Specification
<
FenceAlarmPushLog
>
specification
=
(
root
,
query
,
criteriaBuilder
)
->
{
ArrayList
<
Predicate
>
list
=
new
ArrayList
<>();
if
(
conditionParam
.
getFenceAlarmId
()
!=
null
)
{
list
.
add
(
criteriaBuilder
.
equal
(
root
.
get
(
FenceAlarmPushLog
.
Fields
.
fenceAlarm
),
conditionParam
.
getFenceAlarmId
()
)
);
}
if
(
conditionParam
.
getInformManner
()
!=
null
)
{
CriteriaBuilder
.
In
<
Object
>
in
=
criteriaBuilder
.
in
(
root
.
get
(
FenceAlarmPushLog
.
Fields
.
informManner
));
for
(
Integer
item
:
conditionParam
.
getInformManner
())
{
in
.
value
(
item
);
}
list
.
add
(
in
);
}
if
(
conditionParam
.
getStatus
()
!=
null
)
{
list
.
add
(
criteriaBuilder
.
equal
(
root
.
get
(
FenceAlarmPushLog
.
Fields
.
status
),
conditionParam
.
getStatus
()));
}
if
(
conditionParam
.
getPhone
()
!=
null
)
{
Join
<
Object
,
Object
>
join
=
root
.
join
(
FenceAlarmPushLog
.
Fields
.
user
,
JoinType
.
LEFT
);
list
.
add
(
criteriaBuilder
.
like
(
join
.
get
(
User
.
Fields
.
mobile
),
"%"
+
conditionParam
.
getPhone
()
+
"%"
));
}
Predicate
[]
array
=
list
.
toArray
(
new
Predicate
[
0
]);
return
criteriaBuilder
.
and
(
array
);
};
Page
<
FenceAlarmPushLog
>
page
=
fenceAlarmPushLogRepository
.
findAll
(
specification
,
pageable
);
List
<
FenceAlarmPushLogVo
>
voList
=
page
.
get
().
map
(
FenceAlarmPushLogVo:
:
transform
).
collect
(
Collectors
.
toList
());
PageVo
<
FenceAlarmPushLogVo
>
pageVo
=
PageVo
.
build
(
voList
,
voList
.
size
());
return
Result
.
ok
(
pageVo
);
}
}
app/src/main/java/com/yiring/app/service/location/fence/impl/FenceAlarmServiceImpl.java
浏览文件 @
6411c95b
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
service
.
location
.
fence
.
impl
;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
com.github.liaochong.myexcel.core.DefaultStreamExcelBuilder
;
import
com.yiring.app.domain.location.LocationFence
;
import
com.yiring.app.domain.location.LocationFenceAlarm
;
...
...
@@ -33,6 +35,8 @@ import org.apache.poi.ss.usermodel.Workbook;
import
org.springframework.data.domain.Page
;
import
org.springframework.data.domain.Pageable
;
import
org.springframework.data.jpa.domain.Specification
;
import
org.springframework.messaging.simp.SimpMessagingTemplate
;
import
org.springframework.scheduling.annotation.Async
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
...
...
@@ -53,6 +57,9 @@ public class FenceAlarmServiceImpl implements FenceAlarmService {
private
LocationFenceRepository
locationFenceRepository
;
@Resource
SimpMessagingTemplate
simpMessagingTemplate
;
@Resource
private
MapUtil
mapUtil
;
@Override
...
...
@@ -126,6 +133,24 @@ public class FenceAlarmServiceImpl implements FenceAlarmService {
}
}
@Async
@Override
public
void
alarmPushWeb
(
List
<
LocationFenceAlarm
>
newAlarm
)
{
JSONArray
jsonArray
=
new
JSONArray
();
for
(
LocationFenceAlarm
item
:
newAlarm
)
{
JSONObject
jsonObject
=
new
JSONObject
();
jsonObject
.
put
(
"fence"
,
item
.
getFence
().
getName
());
jsonObject
.
put
(
"map"
,
mapUtil
.
getMapName
(
item
.
getAreaId
().
intValue
()));
jsonObject
.
put
(
"user"
,
item
.
getUser
().
getRealName
());
jsonObject
.
put
(
"tagId"
,
item
.
getTag
().
getId
());
jsonObject
.
put
(
"startTime"
,
item
.
getStartTime
());
jsonObject
.
put
(
"AlarmType"
,
item
.
getType
().
getName
());
jsonObject
.
put
(
"status"
,
item
.
getStatus
().
text
());
jsonArray
.
add
(
jsonObject
);
}
simpMessagingTemplate
.
convertAndSend
(
"/topic/position"
,
jsonArray
.
toJSONString
());
}
private
Specification
<
LocationFenceAlarm
>
getSpecification
(
FenceAlarmConditionParam
param
)
{
return
(
root
,
query
,
criteriaBuilder
)
->
{
ArrayList
<
Predicate
>
list
=
new
ArrayList
<>();
...
...
@@ -138,7 +163,7 @@ public class FenceAlarmServiceImpl implements FenceAlarmService {
}
if
(
param
.
getRealName
()
!=
null
)
{
Join
<
Object
,
Object
>
join
=
root
.
join
(
LocationFenceAlarm
.
Fields
.
user
,
JoinType
.
LEFT
);
list
.
add
(
criteriaBuilder
.
equal
(
join
.
get
(
User
.
Fields
.
realName
),
param
.
getRealName
()
));
list
.
add
(
criteriaBuilder
.
like
(
join
.
get
(
User
.
Fields
.
realName
),
"%"
+
param
.
getRealName
()
+
"%"
));
}
if
(
param
.
getStatus
()
!=
null
)
{
list
.
add
(
...
...
@@ -158,7 +183,7 @@ public class FenceAlarmServiceImpl implements FenceAlarmService {
}
if
(
param
.
getEndTime
()
!=
null
)
{
list
.
add
(
criteriaBuilder
.
lessThanOrEqualTo
(
root
.
get
(
LocationFenceAlarm
.
Fields
.
end
Time
),
param
.
getEndTime
())
criteriaBuilder
.
lessThanOrEqualTo
(
root
.
get
(
LocationFenceAlarm
.
Fields
.
start
Time
),
param
.
getEndTime
())
);
}
Predicate
[]
array
=
list
.
toArray
(
new
Predicate
[
0
]);
...
...
app/src/main/java/com/yiring/app/util/TimeUtil.java
浏览文件 @
6411c95b
...
...
@@ -28,28 +28,26 @@ public class TimeUtil {
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
;
String
beginHour
=
beginTime
.
substring
(
4
,
6
);
String
endHour
=
endTime
.
substring
(
4
,
6
);
String
nowHour
=
source
.
substring
(
3
,
5
);
String
beginMinute
=
beginTime
.
substring
(
7
,
9
);
String
endMinute
=
endTime
.
substring
(
7
,
9
);
String
nowMinute
=
source
.
substring
(
6
,
8
);
String
beginSecond
=
beginTime
.
substring
(
10
);
String
endSecond
=
endTime
.
substring
(
10
);
String
nowSecond
=
source
.
substring
(
9
);
String
beginString
=
beginWeek
+
beginHour
+
beginMinute
+
beginSecond
;
String
endString
=
endWeek
+
endHour
+
endMinute
+
endSecond
;
String
nowString
=
nowWeek
+
nowHour
+
nowMinute
+
nowSecond
;
int
begin
=
Integer
.
parseInt
(
beginString
);
int
end
=
Integer
.
parseInt
(
endString
);
int
now
=
Integer
.
parseInt
(
nowString
);
return
now
>=
begin
&&
now
<=
end
;
}
private
static
int
transform
(
char
source
)
{
...
...
app/src/main/java/com/yiring/app/vo/location/fence/FenceAlarmPushLogVo.java
0 → 100644
浏览文件 @
6411c95b
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
vo
.
location
.
fence
;
import
com.yiring.app.constant.alarm.InformMannerEnum
;
import
com.yiring.app.constant.alarm.ReceiveStatusEnum
;
import
com.yiring.app.domain.location.FenceAlarmPushLog
;
import
io.swagger.annotations.ApiModel
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.time.LocalDateTime
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
org.hibernate.annotations.Comment
;
/**
* @author tml
* @version 1.0
* @date 2022/5/18 9:56
*/
@ApiModel
(
"围栏报警推送记录"
)
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public
class
FenceAlarmPushLogVo
implements
Serializable
{
@Serial
private
static
final
long
serialVersionUID
=
4628469269093052929L
;
@Comment
(
"报警接受人"
)
private
String
name
;
@Comment
(
"联系电话"
)
private
String
phone
;
@Comment
(
"通知方式: 1-app消息 2-短信通知 3-电话通知"
)
private
String
informManner
;
@Comment
(
"通知状态: 1-成功 2-失败"
)
private
String
status
;
@Comment
(
"接受时间"
)
private
LocalDateTime
time
;
public
static
FenceAlarmPushLogVo
transform
(
FenceAlarmPushLog
pushLog
)
{
return
FenceAlarmPushLogVo
.
builder
()
.
name
(
pushLog
.
getUser
().
getRealName
()
+
"("
+
pushLog
.
getUser
().
getDepartment
().
getName
()
+
")"
)
.
phone
(
pushLog
.
getUser
().
getMobile
())
.
informManner
(
InformMannerEnum
.
getByCode
(
pushLog
.
getInformManner
()))
.
status
(
ReceiveStatusEnum
.
getByCode
(
pushLog
.
getStatus
()))
.
time
(
pushLog
.
getTime
())
.
build
();
}
}
app/src/main/java/com/yiring/app/vo/location/fence/FenceAlarmVo.java
浏览文件 @
6411c95b
...
...
@@ -4,12 +4,14 @@ package com.yiring.app.vo.location.fence;
import
com.fasterxml.jackson.databind.annotation.JsonSerialize
;
import
com.fasterxml.jackson.databind.ser.std.ToStringSerializer
;
import
com.yiring.app.constant.alarm.FenceTypeEnum
;
import
com.yiring.app.constant.alarm.InformMannerEnum
;
import
com.yiring.app.domain.location.LocationFenceAlarm
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModelProperty
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.time.LocalDateTime
;
import
java.util.stream.Collectors
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
...
...
@@ -70,7 +72,22 @@ public class FenceAlarmVo implements Serializable {
@ApiModelProperty
(
value
=
"报警状态"
,
example
=
"报警中"
)
private
String
statusName
;
@ApiModelProperty
(
value
=
"通知方式"
,
example
=
"app消息, 短信, 电话"
)
private
String
informManner
;
public
static
FenceAlarmVo
transform
(
LocationFenceAlarm
fenceAlarm
)
{
String
recipient
=
fenceAlarm
.
getPushLogs
()
.
stream
()
.
map
(
e
->
e
.
getUser
().
getRealName
())
.
distinct
()
.
collect
(
Collectors
.
joining
(
", "
));
String
informManner
=
fenceAlarm
.
getPushLogs
()
.
stream
()
.
map
(
e
->
InformMannerEnum
.
getByCode
(
e
.
getInformManner
()))
.
distinct
()
.
collect
(
Collectors
.
joining
(
", "
));
return
FenceAlarmVo
.
builder
()
.
id
(
fenceAlarm
.
getId
())
...
...
@@ -83,9 +100,9 @@ public class FenceAlarmVo implements Serializable {
.
startTime
(
fenceAlarm
.
getStartTime
())
.
endTime
(
fenceAlarm
.
getEndTime
())
.
alarmTypeName
(
fenceAlarm
.
getType
().
getName
())
//todo
//.recipient()
.
recipient
(
recipient
)
.
statusName
(
fenceAlarm
.
getStatus
().
text
())
.
informManner
(
informManner
)
.
build
();
}
}
app/src/main/java/com/yiring/app/web/alarm/AlarmTypeController.java
浏览文件 @
6411c95b
...
...
@@ -4,6 +4,7 @@ package com.yiring.app.web.alarm;
import
com.yiring.app.constant.alarm.FenceTypeEnum
;
import
com.yiring.app.constant.alarm.RelevanceParamEnum
;
import
com.yiring.app.domain.alarm.AlarmType
;
import
com.yiring.app.job.FenceAlarmJob
;
import
com.yiring.app.param.alarm.AlarmConditionParam
;
import
com.yiring.app.param.alarm.AlarmTypeAddParam
;
import
com.yiring.app.param.alarm.AlarmTypeModifyParam
;
...
...
@@ -45,6 +46,9 @@ public class AlarmTypeController {
@Resource
private
AlarmService
alarmService
;
@Resource
private
FenceAlarmJob
fenceAlarmJob
;
@ApiOperation
(
value
=
"添加报警类型"
)
@PostMapping
(
"/addAlarmType"
)
public
Result
<
String
>
addAlarmType
(
@Valid
AlarmTypeAddParam
param
)
{
...
...
@@ -101,4 +105,10 @@ public class AlarmTypeController {
public
void
exportAlarmType
(
@Valid
AlarmConditionParam
conditionParam
,
HttpServletResponse
response
)
{
alarmService
.
exportAlarmType
(
conditionParam
,
response
);
}
@ApiOperation
(
value
=
"test"
)
@PostMapping
(
"/test"
)
public
void
test
()
{
fenceAlarmJob
.
scanAlarmHandler
();
}
}
app/src/main/java/com/yiring/app/web/analysis/history/HistoryRouteController.java
浏览文件 @
6411c95b
...
...
@@ -5,6 +5,7 @@ import com.yiring.app.param.analysis.history.HistoryRouteConditionParam;
import
com.yiring.app.service.analysis.history.HistoryRouteService
;
import
com.yiring.app.vo.analysis.history.HistoryRouteVo
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.param.PageParam
;
import
com.yiring.common.vo.PageVo
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
...
...
@@ -13,6 +14,7 @@ import javax.servlet.http.HttpServletResponse;
import
javax.validation.Valid
;
import
org.springframework.http.MediaType
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
...
...
@@ -39,6 +41,15 @@ public class HistoryRouteController {
return
historyRouteService
.
findByCondition
(
param
);
}
@ApiOperation
(
"分页查询历史轨迹"
)
@GetMapping
(
"/findByPage"
)
public
Result
<
PageVo
<
HistoryRouteVo
>>
findByPage
(
@Valid
HistoryRouteConditionParam
param
,
@Valid
PageParam
pageParam
)
{
return
historyRouteService
.
findByPage
(
param
,
pageParam
);
}
@ApiOperation
(
value
=
"导出历史轨迹"
,
produces
=
MediaType
.
APPLICATION_OCTET_STREAM_VALUE
)
@PostMapping
(
"/exportHistoryRoute"
)
public
void
exportHistoryRoute
(
@Valid
HistoryRouteConditionParam
param
,
HttpServletResponse
response
)
{
...
...
app/src/main/java/com/yiring/app/web/location/fence/FenceAlarmPushLogController.java
0 → 100644
浏览文件 @
6411c95b
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
web
.
location
.
fence
;
import
com.yiring.app.param.location.fence.FenceAlarmPushLogConditionParam
;
import
com.yiring.app.service.location.fence.FenceAlarmPushLogService
;
import
com.yiring.app.vo.location.fence.FenceAlarmPushLogVo
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.param.PageParam
;
import
com.yiring.common.vo.PageVo
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
javax.annotation.Resource
;
import
javax.validation.Valid
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/**
* @author tml
* @version 1.0
* @date 2022/5/18 10:21
*/
@Api
(
tags
=
"围栏报警推送记录"
)
@RestController
@RequestMapping
(
"/push/log"
)
public
class
FenceAlarmPushLogController
{
@Resource
private
FenceAlarmPushLogService
fenceAlarmPushLogService
;
@ApiOperation
(
value
=
"查询推送记录列表"
)
@GetMapping
(
"/findList"
)
public
Result
<
PageVo
<
FenceAlarmPushLogVo
>>
findList
(
@Valid
FenceAlarmPushLogConditionParam
conditionParam
,
@Valid
PageParam
pageParam
)
{
return
fenceAlarmPushLogService
.
findList
(
conditionParam
,
pageParam
);
}
}
app/src/main/java/com/yiring/app/web/location/rule/LocationAlarmRuleController.java
浏览文件 @
6411c95b
...
...
@@ -33,7 +33,7 @@ import org.springframework.web.bind.annotation.*;
@Validated
@SuppressWarnings
({
"deprecation"
})
@Api
(
tags
=
"报警规则"
,
description
=
"AlarmRule"
)
@Api
(
tags
=
"报警规则
:报警给谁
"
,
description
=
"AlarmRule"
)
@RestController
@RequestMapping
(
"/alarm/rule"
)
public
class
LocationAlarmRuleController
{
...
...
app/src/main/java/com/yiring/app/web/location/rule/LocationFenceRuleController.java
浏览文件 @
6411c95b
...
...
@@ -27,7 +27,7 @@ import org.springframework.web.bind.annotation.RestController;
@Validated
@SuppressWarnings
({
"deprecation"
})
@Api
(
tags
=
"
电子围栏报警规则
"
,
description
=
"FenceRule"
)
@Api
(
tags
=
"
报警规则:什么情况报警
"
,
description
=
"FenceRule"
)
@RestController
@RequestMapping
(
"/location/rule"
)
public
class
LocationFenceRuleController
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论