Project 'basic/basic-api-project' was moved to 'basic/basic-api-boot'. Please update any links and bookmarks that may still have the old path.
提交 b408b1ef 作者: 方治民

合并分支 'revert-ebe14c5d' 到 'beta'

撤销 "合并分支 'dev_lijing' 到 'beta'"

查看合并请求 basic/basic-api-project!9
流水线 #107 已取消 于阶段
in 26 秒
...@@ -38,4 +38,3 @@ out/ ...@@ -38,4 +38,3 @@ out/
node_modules node_modules
logs/ logs/
.jpb/
...@@ -3,9 +3,9 @@ variables: ...@@ -3,9 +3,9 @@ variables:
# 本地镜像地址,用于拉取镜像以及发布 # 本地镜像地址,用于拉取镜像以及发布
REGISTRY_REMOTE: localhost:18500 REGISTRY_REMOTE: localhost:18500
# 容器名称 # 容器名称
CONTAINER_NAME: kshg-api CONTAINER_NAME: basic-api
# 对外访问端口 # 对外访问端口
EXPOSE_PORT: 18181 EXPOSE_PORT: 8081
# Pipelines 步骤 # Pipelines 步骤
stages: stages:
...@@ -59,7 +59,7 @@ deploy-job: ...@@ -59,7 +59,7 @@ deploy-job:
# 尝试删除上一个容器 # 尝试删除上一个容器
- id=$(docker ps -aqf name=$CONTAINER_NAME) && [ "$id" ] && docker rm -f $id || true - id=$(docker ps -aqf name=$CONTAINER_NAME) && [ "$id" ] && docker rm -f $id || true
# 在本地运行构建好的镜像 # 在本地运行构建好的镜像
- docker run -d --name $CONTAINER_NAME -p $EXPOSE_PORT:8181 -p 9999:9999 $TAG - docker run -d --name $CONTAINER_NAME -p $EXPOSE_PORT:8081 $TAG
variables: variables:
# 设置镜像 tag,使用 git tag 标识作为镜像 tag # 设置镜像 tag,使用 git tag 标识作为镜像 tag
TAG: $REGISTRY_REMOTE/basic/$CONTAINER_NAME:$CI_BUILD_REF_NAME TAG: $REGISTRY_REMOTE/basic/$CONTAINER_NAME:$CI_BUILD_REF_NAME
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PersistenceUnitSettings">
<persistence-units>
<persistence-unit name="Default">
<packages>
<package value="com.yiring.common.config" />
</packages>
</persistence-unit>
</persistence-units>
</component>
</project>
\ No newline at end of file
...@@ -17,7 +17,7 @@ COPY app/build/libs/app-0.0.1-SNAPSHOT.jar app.jar ...@@ -17,7 +17,7 @@ COPY app/build/libs/app-0.0.1-SNAPSHOT.jar app.jar
# RUN bash -c "touch /app.jar" # RUN bash -c "touch /app.jar"
# 声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务 # 声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务
EXPOSE 8181 9999 EXPOSE 8081
# 指定容器启动程序及参数 <ENTRYPOINT> "<CMD>" # 指定容器启动程序及参数 <ENTRYPOINT> "<CMD>"
ENTRYPOINT ["java", "-jar", "app.jar", "--spring.profiles.active=beta"] ENTRYPOINT ["java", "-jar", "app.jar", "--spring.profiles.active=beta"]
# 可赛化工安全生产平台 API # Basic API(Template)
> 项目 Fork 自 [basic-api-project](https://gitlab.yiring.com/basic/basic-api-project)
## 开发环境 ## 开发环境
...@@ -29,13 +27,5 @@ ...@@ -29,13 +27,5 @@
- [x] [conventional-changelog](https://www.cnblogs.com/mengfangui/p/12634845.html) - [x] [conventional-changelog](https://www.cnblogs.com/mengfangui/p/12634845.html)
- [x] 用户及权限模块(目录/菜单/按钮),预览初始化权限配置 [SQL 脚本](./basic-auth/src/main/resources/init-test-mysql.sql) - [x] 用户及权限模块(目录/菜单/按钮),预览初始化权限配置 [SQL 脚本](./basic-auth/src/main/resources/init-test-mysql.sql)
- [x] 通用文件上传模块 - [x] 通用文件上传模块
- [x] 通用字典管理模块 - [ ] 通用字典管理模块
- [x] XXL-JOB 定时任务模块 - [ ] XXL-JOB 定时任务模块
- [ ] 扩展 PostgresDialect 实现时序查询函数
---
> 引用
1. [JTS](https://github.com/locationtech/jts)
2. [GeoTools](http://docs.geotools.org/)
3. [PostGIS](https://blog.csdn.net/qq_27816785/article/details/124540160)
dependencies {
implementation project(':basic-common:core')
implementation project(':basic-common:util')
implementation project(':basic-common:redis')
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-amqp'
// 本地依赖
implementation fileTree(dir: project.rootDir.getPath() + '\\libs', includes: ['*jar'])
// 文档及参数校验
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation "io.swagger:swagger-annotations:${swaggerAnnotationsVersion}"
// hutool-core
implementation "cn.hutool:hutool-core:${hutoolVersion}"
implementation "cn.hutool:hutool-http:${hutoolVersion}"
// fastjson
implementation "com.alibaba:fastjson:${fastJsonVersion}"
// https://github.com/vladmihalcea/hibernate-types
// hibernate-types-55
implementation "com.vladmihalcea:hibernate-types-55:${hibernateTypesVersion}"
// ======================= 推送相关 =======================
// 个推 SDK(App 推送)
// https://mvnrepository.com/artifact/com.getui.push/restful-sdk
implementation 'com.getui.push:restful-sdk:1.0.0.6'
// 阿里云短信 SDK(SMS 推送)
// https://mvnrepository.com/artifact/com.aliyun/dysmsapi20170525
implementation 'com.aliyun:dysmsapi20170525:2.0.9'
// 邮件 SDK(EMAIL 推送)
implementation 'org.springframework.boot:spring-boot-starter-mail'
// ======================================================
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.push.domain;
import com.alibaba.fastjson.JSONObject;
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
import com.yiring.common.domain.BasicEntity;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Objects;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.TypeDef;
/**
* 推送消息日志
*
* @author Jim
* @version 0.1
* 2022/4/14 14:55
*/
@Getter
@Setter
@ToString
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
@Table(
name = "SYS_PUSH_MESSAGE",
indexes = {
@Index(columnList = "type"),
@Index(columnList = "status"),
@Index(columnList = "source"),
@Index(columnList = "sourceId"),
@Index(columnList = "target"),
@Index(columnList = "targetId"),
@Index(columnList = "pushTime"),
}
)
@Comment("推送消息日志")
public class PushMessage extends BasicEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1478640364892356248L;
@Comment("消息类型")
@Enumerated(EnumType.STRING)
Type type;
@Comment("消息来源")
String source;
@Comment("消息来源标识")
String sourceId;
@Comment("消息目标")
String target;
@Comment("消息目标标识")
String targetId;
@Comment("消息内容")
String content;
@Comment("扩展数据")
@org.hibernate.annotations.Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
JSONObject extra;
@Comment("消息状态")
@Enumerated(EnumType.STRING)
Status status;
@Comment("推送反馈结果")
@org.hibernate.annotations.Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
JSONObject result;
@Comment("重试次数")
Integer retryCount;
@Comment("推送时间")
LocalDateTime pushTime;
@SuppressWarnings({ "unused" })
public enum Type {
WEBHOOK("webhook"),
APP("APP 消息"),
SMS("短信消息"),
EMAIL("邮件消息"),
CALL_TTS("TTS 文本合成语音消息(电话)"),
CALL_AUDIO("自定义音频消息(电话)"),
DEVICE_TONE("自定义音频消息(音柱)");
final String text;
Type(String text) {
this.text = text;
}
public String text() {
return this.text;
}
public String queue() {
return String.format("push.%s.queue", this.name().toLowerCase());
}
}
@SuppressWarnings({ "unused" })
public enum Status {
SUCCESS("成功"),
FAIL("失败");
final String text;
Status(String text) {
this.text = text;
}
public String text() {
return this.text;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
PushMessage that = (PushMessage) o;
return getId() != null && Objects.equals(getId(), that.getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.push.domain;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* @author Jim
* @version 0.1
* 2022/4/14 15:33
*/
@Repository
public interface PushMessageRepository
extends JpaRepository<PushMessage, Serializable>, JpaSpecificationExecutor<PushMessage> {}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.push.param;
import io.swagger.annotations.ApiModel;
import lombok.*;
import lombok.experimental.FieldDefaults;
/**
* App 推送参数
*
* @author Jim
* @version 0.1
* 2022/4/21 10:27
*/
@ApiModel("A")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class PushAppParam {
String webhook;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.push.rabbitmq;
import java.util.HashMap;
import java.util.Map;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 推送 rabbitmq 配置
*
* @author ifzm
* 2019/8/21 15:44
*/
@Configuration
public class PushRabbitConfig {
/**
* 消息交换机
*/
public static final String PUSH_TOPIC_EXCHANGE = "push.topic.exchange";
/**
* WebHook 推送队列
*/
public static final String PUSH_WEBHOOK_QUEUE = "push.webhook.queue";
/**
* App 消息推送队列
*/
public static final String PUSH_APP_QUEUE = "push.app.queue";
/**
* 短信推送队列
*/
public static final String PUSH_SMS_QUEUE = "push.sms.queue";
/**
* 邮箱推送队列
*/
public static final String PUSH_MAIL_QUEUE = "push.mail.queue";
/**
* TTS 语音电话队列
*/
public static final String PUSH_CALL_TTS_QUEUE = "push.call.tts.queue";
/**
* 语音电话推送队列
*/
public static final String PUSH_CALL_AUDIO_QUEUE = "push.call.audio.queue";
/**
* 设备广播推送队列
*/
public static final String PUSH_DEVICE_TONE_QUEUE = "push.device.tone.queue";
/**
* 订阅模式
*
* @return TopicExchange
*/
@Bean
TopicExchange exchange() {
return new TopicExchange(PUSH_TOPIC_EXCHANGE, true, false);
}
@Bean(PUSH_APP_QUEUE)
public Queue pushAppQueue() {
Map<String, Object> args = new HashMap<>(1);
args.put("x-message-ttl", 60 * 1000);
return new Queue(PUSH_APP_QUEUE, true, false, false, args);
}
@Bean
Binding bindingExchangeApp(@Qualifier(PUSH_APP_QUEUE) Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(PUSH_APP_QUEUE);
}
@Bean(PUSH_WEBHOOK_QUEUE)
public Queue pushWebHookQueue() {
Map<String, Object> args = new HashMap<>(1);
args.put("x-message-ttl", 30 * 1000);
return new Queue(PUSH_WEBHOOK_QUEUE, true, false, false, args);
}
@Bean
Binding bindingExchangeWebHook(@Qualifier(PUSH_WEBHOOK_QUEUE) Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(PUSH_WEBHOOK_QUEUE);
}
@Bean(PUSH_SMS_QUEUE)
public Queue pushSmsQueue() {
Map<String, Object> args = new HashMap<>(1);
args.put("x-message-ttl", 30 * 1000);
return new Queue(PUSH_SMS_QUEUE, true, false, false, args);
}
@Bean
Binding bindingExchangeSms(@Qualifier(PUSH_SMS_QUEUE) Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(PUSH_SMS_QUEUE);
}
@Bean(PUSH_MAIL_QUEUE)
public Queue pushMailQueue() {
Map<String, Object> args = new HashMap<>(1);
args.put("x-message-ttl", 60 * 1000);
return new Queue(PUSH_MAIL_QUEUE, true, false, false, args);
}
@Bean
Binding bindingExchangeMail(@Qualifier(PUSH_MAIL_QUEUE) Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(PUSH_MAIL_QUEUE);
}
@Bean(PUSH_CALL_TTS_QUEUE)
public Queue pushCallTtsQueue() {
Map<String, Object> args = new HashMap<>(1);
args.put("x-message-ttl", 60 * 10 * 1000);
return new Queue(PUSH_CALL_TTS_QUEUE, true, false, false, args);
}
@Bean
Binding bindingExchangeCallTts(@Qualifier(PUSH_CALL_TTS_QUEUE) Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(PUSH_CALL_TTS_QUEUE);
}
@Bean(PUSH_CALL_AUDIO_QUEUE)
public Queue pushCallAudioQueue() {
Map<String, Object> args = new HashMap<>(1);
args.put("x-message-ttl", 60 * 10 * 1000);
return new Queue(PUSH_CALL_AUDIO_QUEUE, true, false, false, args);
}
@Bean
Binding bindingExchangeCallAudio(@Qualifier(PUSH_CALL_AUDIO_QUEUE) Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(PUSH_CALL_AUDIO_QUEUE);
}
@Bean(PUSH_DEVICE_TONE_QUEUE)
public Queue pushDeviceToneQueue() {
Map<String, Object> args = new HashMap<>(1);
args.put("x-message-ttl", 60 * 10 * 1000);
return new Queue(PUSH_DEVICE_TONE_QUEUE, true, false, false, args);
}
@Bean
Binding bindingExchangeDeviceTone(@Qualifier(PUSH_DEVICE_TONE_QUEUE) Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(PUSH_DEVICE_TONE_QUEUE);
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.push.rabbitmq;
import com.yiring.app.push.domain.PushMessageRepository;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
/**
* rabbitmq配置
*
* @author ifzm
* 2019/8/21 16:07
*/
@SuppressWarnings({ "unused" })
@Slf4j
@Component("PushRabbitReceiver")
@Transactional(rollbackFor = Exception.class)
public class PushRabbitReceiver {
@Resource
PushMessageRepository repository;
@RabbitHandler
@RabbitListener(queues = PushRabbitConfig.PUSH_WEBHOOK_QUEUE)
public void receiverWebHookMessage(Long id) {
log.info("[WebHook] Message: " + id);
repository.findById(id).ifPresent(message -> log.info("{}", message));
// TODO
// 实现调用 WebHook,基于 WebHook API 发起 HTTPs 请求
}
@RabbitHandler
@RabbitListener(queues = PushRabbitConfig.PUSH_APP_QUEUE)
public void receiverAppMessage(Long id) {
log.info("[App] Message: " + id);
// TODO
// 实现推送消息到 App,基于个推 API
// https://github.com/GetuiLaboratory/getui-pushapi-java-client-v2
}
@RabbitHandler
@RabbitListener(queues = PushRabbitConfig.PUSH_SMS_QUEUE)
public void receiverSmsMessage(Long id) {
log.info("[SMS] Message: " + id);
// TODO
// 实现发送短信,基于阿里云短信平台 API
}
@RabbitHandler
@RabbitListener(queues = PushRabbitConfig.PUSH_MAIL_QUEUE)
public void receiverMailMessage(Long id) {
log.info("[Mail] Message: " + id);
// TODO
// 实现发送邮件,基于邮件配置
}
@RabbitHandler
@RabbitListener(queues = PushRabbitConfig.PUSH_CALL_TTS_QUEUE)
public void receiverTtsMessage(Long id) {
log.info("[Phone TTS] Message: " + id);
// TODO
// 实现拨打电话播放 TTS 转语音,基于壹润外呼系统 API
}
@RabbitHandler
@RabbitListener(queues = PushRabbitConfig.PUSH_CALL_AUDIO_QUEUE)
public void receiverAudioMessage(Long id) {
log.info("[Phone Audio] Message: " + id);
// TODO
// 实现拨打电话播放音频文件,基于壹润外呼系统 API
}
@RabbitHandler
@RabbitListener(queues = PushRabbitConfig.PUSH_DEVICE_TONE_QUEUE)
public void receiverToneMessage(Long id) {
log.info("[Device Tone] Message: " + id);
// TODO
// 实现播放设备铃声,基于音柱广播设备 API
// SDK 暂未拿到,设备未采购,未进行联调
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.push.service;
import com.alibaba.fastjson.JSONObject;
import com.yiring.app.push.domain.PushMessage;
import com.yiring.app.push.param.PushAppParam;
/**
* 推送服务
*
* @author Jim
* @version 0.1
* 2022/4/14 16:01
*/
public interface PushService {
void push(PushMessage.Type type, JSONObject raw);
/**
* 推送到 App
* @param param 参数
*/
void app(PushAppParam param);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.push.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.yiring.app.push.domain.PushMessage;
import com.yiring.app.push.domain.PushMessageRepository;
import com.yiring.app.push.param.PushAppParam;
import com.yiring.app.push.rabbitmq.PushRabbitConfig;
import com.yiring.app.push.service.PushService;
import javax.annotation.Resource;
import javax.transaction.Transactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
/**
* 推送服务实现
*
* @author Jim
* @version 0.1
* 2022/4/14 16:08
*/
@Slf4j
@Service
@Transactional(rollbackOn = Exception.class)
public class PushServiceImpl implements PushService {
@Resource
PushMessageRepository repository;
@Resource
RabbitTemplate rabbitTemplate;
@Override
public void push(PushMessage.Type type, JSONObject raw) {
PushMessage message = new PushMessage();
message.setType(type);
message.setExtra(raw);
repository.saveAndFlush(message);
rabbitTemplate.convertAndSend(PushRabbitConfig.PUSH_TOPIC_EXCHANGE, type.queue(), message.getId());
}
@Override
public void app(PushAppParam param) {}
}
...@@ -9,17 +9,11 @@ dependencies { ...@@ -9,17 +9,11 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-amqp'
implementation "org.springframework.boot:spring-boot-starter-websocket"
implementation "org.springframework.boot:spring-boot-starter-reactor-netty"
implementation "org.springframework.cloud:spring-cloud-starter-openfeign"
implementation "org.springframework.cloud:spring-cloud-commons"
// 💬 Mock/Test Env // 💬 Mock/Test Env
runtimeOnly 'com.h2database:h2' runtimeOnly 'com.h2database:h2'
// 💬 Prod/Dev Env // 💬 Prod/Dev Env
// runtimeOnly 'mysql:mysql-connector-java' runtimeOnly 'mysql:mysql-connector-java'
runtimeOnly 'org.postgresql:postgresql' // runtimeOnly 'org.postgresql:postgresql'
// 本地依赖 // 本地依赖
implementation fileTree(dir: project.rootDir.getPath() + '\\libs', includes: ['*jar']) implementation fileTree(dir: project.rootDir.getPath() + '\\libs', includes: ['*jar'])
...@@ -28,9 +22,6 @@ dependencies { ...@@ -28,9 +22,6 @@ dependencies {
implementation project(":basic-common:core") implementation project(":basic-common:core")
implementation project(":basic-common:util") implementation project(":basic-common:util")
// 服务依赖
implementation project(":app-push")
// Optional: Redis // Optional: Redis
implementation project(":basic-common:redis") implementation project(":basic-common:redis")
...@@ -47,37 +38,17 @@ dependencies { ...@@ -47,37 +38,17 @@ dependencies {
// FIX: minio dep // FIX: minio dep
implementation "com.squareup.okhttp3:okhttp:${okhttpVersion}" implementation "com.squareup.okhttp3:okhttp:${okhttpVersion}"
// Optional: MyBatis Plus
implementation "com.baomidou:mybatis-plus-boot-starter:${mybatisPlusVersion}"
// fastjson // fastjson
implementation "com.alibaba:fastjson:${fastJsonVersion}" implementation "com.alibaba:fastjson:${fastJsonVersion}"
// hutool // hutool
implementation "cn.hutool:hutool-core:${hutoolVersion}" implementation "cn.hutool:hutool-core:${hutoolVersion}"
implementation "cn.hutool:hutool-extra:${hutoolVersion}" implementation "cn.hutool:hutool-extra:${hutoolVersion}"
implementation "cn.hutool:hutool-http:${hutoolVersion}"
implementation "cn.hutool:hutool-json:${hutoolVersion}"
// JPA 增加空间字段支持
// https://blog.wuwii.com/jpa-spatial.html
implementation("org.hibernate:hibernate-spatial:${hibernateSpatialVersion}") {
exclude group: 'org.postgresql', module: 'postgresql'
}
// JTS 几何对象操作库
implementation "org.locationtech.jts:jts-core:${jtsVersion}"
// https://github.com/vladmihalcea/hibernate-types // https://github.com/vladmihalcea/hibernate-types
// hibernate-types-55 // hibernate-types-55
implementation "com.vladmihalcea:hibernate-types-55:${hibernateTypesVersion}" implementation "com.vladmihalcea:hibernate-types-55:${hibernateTypesVersion}"
// myexcel
implementation "com.github.liaochong:myexcel:${myexcelVersion}"
// feign-okhttp
implementation "io.github.openfeign:feign-okhttp:${feignOkhttpVersion}"
// xxl-job
implementation "com.xuxueli:xxl-job-core:${xxlJobVersion}"
// minio
implementation "io.minio:minio:${minioVersion}"
} }
/* (C) 2021 YiRing, Inc. */ /* (C) 2021 YiRing, Inc. */
package com.yiring.app; package com.yiring.app;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters; import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@MapperScan(basePackages = Application.BASE_PACKAGES + ".app.mapper")
@EnableJpaRepositories(basePackages = Application.BASE_PACKAGES) @EnableJpaRepositories(basePackages = Application.BASE_PACKAGES)
@EntityScan( @EntityScan(
basePackageClasses = { Application.class, Jsr310JpaConverters.class }, basePackageClasses = { Application.class, Jsr310JpaConverters.class },
basePackages = Application.BASE_PACKAGES basePackages = Application.BASE_PACKAGES
) )
@EnableFeignClients
@EnableJpaAuditing
@SpringBootApplication(scanBasePackages = Application.BASE_PACKAGES) @SpringBootApplication(scanBasePackages = Application.BASE_PACKAGES)
public class Application { public class Application {
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.config;
import cn.hutool.core.util.StrUtil;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import javax.annotation.Resource;
import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* xxl-job 配置
*/
@Slf4j
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
@Configuration
@ConfigurationProperties(prefix = "xxl.job")
public class XxlJobConfig {
@Resource
InetUtils inetUtils;
String adminAddresses;
String accessToken;
String executorAppName;
String executorAddress;
String executorIp;
Integer executorPort = 9999;
String executorLogPath;
Integer executorLogRetentionDays = 30;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
log.info(">>>>>>>>>>> xxl-job init: {}", adminAddresses);
if (StrUtil.isBlank(executorIp)) {
executorIp = inetUtils.findFirstNonLoopbackAddress().getHostAddress();
}
if (StrUtil.isBlank(executorAddress)) {
executorAddress = "http://" + executorIp + ":" + executorPort;
}
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(executorAppName);
xxlJobSpringExecutor.setAddress(executorAddress);
xxlJobSpringExecutor.setIp(executorIp);
xxlJobSpringExecutor.setPort(executorPort);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(executorLogPath);
xxlJobSpringExecutor.setLogRetentionDays(executorLogRetentionDays);
return xxlJobSpringExecutor;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.config.dialect;
import java.io.Serial;
import org.hibernate.spatial.dialect.postgis.PostgisPG10Dialect;
/**
* Postgres 方言
* TODO: 扩展 TimescaleDB 查询函数相关
*
* @author Jim
* @version 0.1
* 2022/4/7 16:11
*/
@SuppressWarnings({ "unused" })
public class PostgresDialect extends PostgisPG10Dialect {
@Serial
private static final long serialVersionUID = 187383913873678550L;
public PostgresDialect() {
super();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.constant;
/**
* Redis Key 常量类
*
* @author fangzhimin
* 2018/9/4 15:51
*/
public interface RedisKey {
/**
* STOMP 在线用户关键数据
*/
String STOMP_ONLINE_USERS = "STOMP_ONLINE_USERS";
/**
* 地图信息
*/
String ZY_MAP_AREAS = "ZY_MAP_AREAS";
}
/* (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/4/27 13:36
*/
public enum FenceTypeEnum {
/**
* 普通围栏
*/
ORDINARY(1, "普通围栏"),
/**
* 特殊作业
*/
SPECIAL(2, "特殊作业"),
/**
* 重大危险源
*/
DANGEROUS(3, "重大危险源");
private static final List<CodeNameVo> LIST;
public static final int MIN = 1;
public static final int MAX = 3;
public static final int TOTAL = 3;
static {
LIST = new ArrayList<>();
for (FenceTypeEnum item : values()) {
LIST.add(CodeNameVo.builder().code(item.code).name(item.name).build());
}
}
@Getter
private final Integer code;
@Getter
private final String name;
FenceTypeEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
/**
* 根据key获取value
* @param code 围栏类别key
* @return 围栏类别
*/
public static String getByCode(Integer code) {
if (code != null) {
for (FenceTypeEnum item : values()) {
if (item.code.equals(code)) {
return item.name;
}
}
}
throw new RuntimeException("FenceTypeEnum获取未知围栏类别");
}
/**
* 获取所有围栏类别
* @return 所有围栏类别集合
*/
public static List<CodeNameVo> getAll() {
return LIST;
}
}
/* (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/5 16:05
*/
public enum InformMannerEnum {
/**
* app消息通知
*/
APP(1, "app消息"),
/**
* 短信通知
*/
MESSAGES(2, "短信通知"),
/**
* 电话通知
*/
PHONE(3, "电话通知");
@Getter
private final Integer code;
@Getter
private final String name;
private static final List<CodeNameVo> LIST;
static {
LIST = new ArrayList<>();
for (InformMannerEnum item : values()) {
LIST.add(new CodeNameVo(item.code, item.name));
}
}
InformMannerEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
public static String getByCode(Integer code) {
for (InformMannerEnum item : values()) {
if (item.getCode().equals(code)) {
return item.getName();
}
}
throw new RuntimeException("InformMannerEnum获取未知通知类型");
}
public static List<CodeNameVo> getAll() {
return LIST;
}
}
/* (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();
}
}
throw new RuntimeException("ReceiveStatusEnum获取未知状态");
}
public static List<CodeNameVo> findAll() {
return LIST;
}
}
/* (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/4/27 13:43
*/
public enum RelevanceParamEnum {
/**
* 最大人数
*/
MAX_PEOPLE_NUMBER(1, "最多人数"),
/**
* 最小人数
*/
MIN_PEOPLE_NUMBER(2, "最少人数"),
/**
* 允许进入人员
*/
ALLOW_ENTRANCE(3, "允许进入人员"),
/**
* 不允许离开人员
*/
NOT_ALLOW_LEAVE(4, "不允许离开人员"),
/**
* 静止时长
*/
STATIC_DURATION(5, "静止时长(分钟)"),
/**
* 滞留时长
*/
RETENTION_DURATION(6, "滞留时长(分钟)"),
/**
* 触发报警距离
*/
TRIGGER_ALARM_DISTANCE(7, "触发报警距离");
private static final List<CodeNameVo> LIST;
public static final int MIN = 1;
public static final int MAX = 7;
public static final int TOTAL = 7;
static {
LIST = new ArrayList<>();
for (RelevanceParamEnum item : values()) {
LIST.add(CodeNameVo.builder().code(item.code).name(item.name).build());
}
}
@Getter
private final Integer code;
@Getter
private final String name;
RelevanceParamEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
/**
* 根据key获取value
* @param code 关联参数key
* @return 关联参数
*/
public static String getByCode(Integer code) {
if (code != null) {
for (RelevanceParamEnum item : values()) {
if (item.code.equals(code)) {
return item.name;
}
}
}
throw new RuntimeException("RelevanceParamEnum获取未知关联参数");
}
/**
* 获取所有关联参数
* @return 所有关联参数集合
*/
public static List<CodeNameVo> getAll() {
return LIST;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.constant.rehearsal;
import com.yiring.app.vo.CodeNameVo;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
/**
* 演练计划状态枚举(1:未启动, 2:进行中, 3:已结束)
* @author tml
* @version 1.0
* @date 2022/5/9 17:29
*/
public enum RehearsalPlanStatusEnum {
/**
*未启动
*/
UN_START(1, "未启动"),
/**
*进行中
*/
RUNNING(2, "进行中"),
/**
* 已结束
*/
END(3, "已结束");
@Getter
private final Integer code;
@Getter
private final String name;
private static final List<CodeNameVo> LIST;
static {
LIST = new ArrayList<>();
for (RehearsalPlanStatusEnum item : values()) {
LIST.add(new CodeNameVo(item.getCode(), item.getName()));
}
}
RehearsalPlanStatusEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
public static List<CodeNameVo> getAll() {
return LIST;
}
public static String getByCode(Integer code) {
for (RehearsalPlanStatusEnum item : values()) {
if (item.getCode().equals(code)) {
return item.getName();
}
}
throw new RuntimeException("RehearsalPlanStatusEnum获取异常状态");
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.constant.rehearsal;
import com.yiring.app.vo.CodeNameVo;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
/**
* 演练计划风险等级枚举(1:红色风险, 2:橙色风险, 3:黄色风险, 4:蓝色风险)
* @author tml
* @version 1.0
* @date 2022/5/9 17:28
*/
public enum RiskLevelEnum {
/**
* 红色风险
*/
RED(1, "红色风险"),
/**
* 橙色风险
*/
ORANGE(2, "橙色风险"),
/**
* 黄色风险
*/
YELLOW(3, "黄色风险"),
/**
* 蓝色风险
*/
BLUE(4, "蓝色风险");
@Getter
private final Integer code;
@Getter
private final String name;
private static final List<CodeNameVo> LIST;
static {
LIST = new ArrayList<>();
for (RiskLevelEnum item : values()) {
LIST.add(new CodeNameVo(item.getCode(), item.getName()));
}
}
RiskLevelEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
public static List<CodeNameVo> getAll() {
return LIST;
}
public static String getByCode(Integer code) {
for (RiskLevelEnum item : values()) {
if (item.getCode().equals(code)) {
return item.getName();
}
}
throw new RuntimeException("RiskLevelEnum获取未知风险");
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.constant.risk;
import com.yiring.app.excel.risk.RiskWarnExcel;
import java.util.ArrayList;
import java.util.List;
/**
* @author tml
* @version 1.0
* @date 2022/5/24 16:32
*/
public class TemplateList {
private static final List<RiskWarnExcel> LIST = new ArrayList<>();
static {
LIST.add(
RiskWarnExcel
.builder()
.workAreaName("BTC产品库房")
.point("112.863173604639,30.4786075211555,0")
.install("产品库房北侧中间立柱东1")
.monitoring("有毒气体报警器")
.locationNum("AT-4736")
.range("0-1.6")
.unit("ppm")
.lowLow("0.15")
.low("0.2")
.high("0.5")
.highHigh("0.55")
.flame("")
.remark("注意:工区、安装位置、监控参数、位号为必填,导入时备注这一列可以删除")
.build()
);
LIST.add(
RiskWarnExcel
.builder()
.workAreaName("计量槽")
.point("112.863173604639,30.4786075211555,0")
.install("1号槽液位")
.monitoring("液位")
.locationNum("PI-2107A")
.range("-27.18-7.32KPa")
.unit("ppm")
.lowLow("3%")
.low("5%")
.high("70%")
.highHigh("73%")
.flame("")
.remark("注意:区间要么都为百分比要么都不为百分比")
.build()
);
LIST.add(
RiskWarnExcel
.builder()
.workAreaName("合成盐酸")
.point("112.863173604639,30.4786075211555,0")
.install("1号炉一楼")
.monitoring("火焰检测")
.locationNum("BSA-1401A")
.range("")
.unit("")
.lowLow("")
.low("")
.high("")
.highHigh("")
.flame("1")
.remark("注意:火焰检测在报警值(熄灭)这里添加预警值,等于这个数值时显示熄灭")
.build()
);
}
public static List<RiskWarnExcel> getTemplateList() {
return LIST;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.constant.risk;
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/23 17:01
*/
public enum ThresholdStatusEnum {
/**
* 低低
*/
LOW_LOW(1, "低低"),
/**
* 低
*/
LOW(2, "低"),
/**
* 高
*/
HIGH(3, "高"),
/**
* 高高
*/
HIGH_HIGH(4, "高高"),
/**
* 熄灭
*/
FLAME_EXTINGUISH(5, "熄灭");
@Getter
private final Integer code;
@Getter
private final String name;
private static final List<CodeNameVo> LIST = new ArrayList<>();
static {
for (ThresholdStatusEnum item : values()) {
LIST.add(new CodeNameVo(item.code, item.name));
}
}
ThresholdStatusEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
public static String getByCode(Integer code) {
for (ThresholdStatusEnum item : values()) {
if (item.code.equals(code)) {
return item.getName();
}
}
throw new RuntimeException("ThresholdStatus获取异常状态");
}
public static List<CodeNameVo> getAll() {
return LIST;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy;
import com.yiring.common.core.Result;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 9:21
*/
@FunctionalInterface
public interface IParamInitStrategy<T> {
/**
* 校验参数
* @param param 参数
* @return 是否成功
*/
Result<String> paramInit(T param);
}
/* (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;
/**
* 扫描是否满足报警策略
* @author tml
* @version 1.0
* @date 2022/5/14 11:05
*/
@FunctionalInterface
public interface IScanAlarmStrategy {
/**
* 判断是否触发报警
* @param param 参数
* @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);
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.fence;
import com.yiring.app.constant.alarm.FenceTypeEnum;
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;
/**
* 重大危险源
* @author tml
* @version 1.0
* @date 2022/4/29 11:08
*/
@Component
public class DangerousStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public DangerousStrategy() {
Integer fenceType = FenceTypeEnum.DANGEROUS.getCode();
LocationFenceTypeContext.register(fenceType, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
//TODO
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.fence;
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;
import org.springframework.stereotype.Component;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 11:15
*/
@Component
public class DefaultStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public DefaultStrategy() {
Integer fenceType = 0;
LocationFenceTypeContext.register(fenceType, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
ruleParam.setVoiceId(null);
ruleParam.setVoiceName(null);
ruleParam.setPlayEquipmentId(null);
ruleParam.setPlayEquipmentName(null);
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.fence;
import com.yiring.app.constant.alarm.FenceTypeEnum;
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;
import lombok.extern.slf4j.Slf4j;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 11:09
*/
@Slf4j
public class LocationFenceTypeContext {
private final IParamInitStrategy<LocationFenceRuleAddParam> checkStrategy;
private static final ConcurrentHashMap<Integer, IParamInitStrategy<LocationFenceRuleAddParam>> FENCE_TYPE_MAP = new ConcurrentHashMap<>(
4
);
public static void register(Integer relevanceParam, IParamInitStrategy<LocationFenceRuleAddParam> strategy) {
FENCE_TYPE_MAP.put(relevanceParam, strategy);
}
public LocationFenceTypeContext(Integer relevanceParam) {
if (relevanceParam == null || relevanceParam > FenceTypeEnum.MAX || relevanceParam < FenceTypeEnum.MIN) {
log.warn("报警类型的关联参数异常, relevanceParam:[{}]", relevanceParam);
throw new RuntimeException("报警类型的关联参数异常");
}
IParamInitStrategy<LocationFenceRuleAddParam> strategy = FENCE_TYPE_MAP.get(relevanceParam);
if (strategy == null) {
strategy = FENCE_TYPE_MAP.get(0);
}
this.checkStrategy = strategy;
}
public Result<String> paramInit(LocationFenceRuleAddParam param) {
return checkStrategy.paramInit(param);
}
}
/* (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.*;
import com.yiring.app.util.TimeUtil;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.auth.domain.user.User;
import com.yiring.auth.domain.user.UserRepository;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import org.springframework.data.jpa.domain.Specification;
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 {
@Resource
private UserRepository userRepository;
public AllowEntranceStrategy() {
Integer relevanceParam = RelevanceParamEnum.ALLOW_ENTRANCE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
ScanAlarmContext.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, "请至少配置一个允许进入的人员");
}
}
//如果只设置星期没有设置时间,则默认时间是全天
for (TimeAndUserParam item : timeAndUser) {
for (TimeParam time : item.getTime()) {
if (time.getWeek() != null) {
if (time.getBeginTime() == null) {
time.setBeginTime("00:00:00");
}
if (time.getEndTime() == null) {
time.setEndTime("23:59:59");
}
}
}
}
//检查配置的员工是否存在
Specification<User> specification = (root, query, criteriaBuilder) -> {
CriteriaBuilder.In<Object> in = criteriaBuilder.in(root.get(User.Fields.uuid));
HashSet<String> ids = new HashSet<>();
for (TimeAndUserParam item : timeAndUser) {
for (RelevanceUserParam userParam : item.getUser()) {
ids.add(userParam.getUuid());
}
}
for (String uuid : ids) {
in.value(uuid);
}
return criteriaBuilder.and(in);
};
Map<String, List<User>> map = userRepository
.findAll(specification)
.stream()
.collect(Collectors.groupingBy(User::getUuid));
for (TimeAndUserParam item : timeAndUser) {
for (RelevanceUserParam userParam : item.getUser()) {
List<User> list = map.get(userParam.getUuid());
if (CollectionUtils.isEmpty(list)) {
return Result.no(Status.EXPECTATION_FAILED, "工号为:" + userParam.getUuid() + "员工不存在");
}
userParam.setRealName(list.get(0).getRealName());
}
}
ruleParam.setDuration(null);
ruleParam.setDistance(null);
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) {
for (TimeParam time : item.getTime()) {
if (TimeUtil.judgeWeek(LocalDateTime.now(), time.getWeek())) {
if (TimeUtil.judgeTime(LocalDateTime.now(), time.getBeginTime(), time.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).name(param.getFenceName()).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不重合的部分代表需要结束的报警
IScanAlarmStrategy.notIntersect(newAlarms, oldAlarms, jobVo);
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.fence.LocationFenceTypeContext;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.util.concurrent.ConcurrentHashMap;
import lombok.extern.slf4j.Slf4j;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 9:36
*/
@Slf4j
public class LocationFenceRuleContext {
private final IParamInitStrategy<LocationFenceRuleAddParam> checkStrategy;
private static final ConcurrentHashMap<Integer, IParamInitStrategy<LocationFenceRuleAddParam>> RULE_MAP = new ConcurrentHashMap<>(
10
);
public static void register(Integer relevanceParam, IParamInitStrategy<LocationFenceRuleAddParam> strategy) {
RULE_MAP.put(relevanceParam, strategy);
}
public LocationFenceRuleContext(Integer relevanceParam) {
if (
relevanceParam == null || relevanceParam > RelevanceParamEnum.MAX || relevanceParam < RelevanceParamEnum.MIN
) {
log.warn("报警类型的关联参数异常, relevanceParam:[{}]", relevanceParam);
throw new RuntimeException("报警类型的关联参数异常");
}
this.checkStrategy = RULE_MAP.get(relevanceParam);
}
public Result<String> paramInit(LocationFenceRuleAddParam param) {
Result<String> result = new LocationFenceTypeContext(param.getFenceType()).paramInit(param);
if (Status.OK.value() != result.getStatus()) {
return result;
}
return checkStrategy.paramInit(param);
}
}
/* (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.*;
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) {
Result.no(Status.EXPECTATION_FAILED, "最大人数不能空或小于零");
}
}
//如果只设置星期没有设置时间,则默认时间是全天
for (TimeAndNumberParam item : timeAndNumber) {
for (TimeParam time : item.getTime()) {
if (time.getWeek() != null) {
if (time.getBeginTime() == null) {
time.setBeginTime("00:00:00");
}
if (time.getEndTime() == null) {
time.setEndTime("23:59:59");
}
}
}
}
//将时间和距离都设为-1
ruleParam.setDuration(null);
ruleParam.setDistance(null);
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;
StringBuilder begin = new StringBuilder();
StringBuilder end = new StringBuilder();
//筛选在当前时间生效的配置
for (TimeAndNumberParam item : timeAndNumberParamList) {
for (TimeParam time : item.getTime()) {
if (TimeUtil.judgeWeek(LocalDateTime.now(), time.getWeek())) {
if (TimeUtil.judgeTime(LocalDateTime.now(), time.getBeginTime(), time.getEndTime())) {
begin.append(time.getWeek()).append(" ").append(time.getBeginTime());
end.append(time.getWeek()).append(" ").append(time.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<>();
//查询围栏内人员进入时的信息
List<LocationTurnover> turnoverList = locationTurnoverRepository.withinFence(fenceId, true);
//筛选出在配置时间段内进入的进出信息
turnoverList =
turnoverList
.stream()
.filter(e -> TimeUtil.judgeWeekTime(e.getTime(), begin.toString(), end.toString()))
.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).name(param.getFenceName()).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不重合的部分代表需要结束的报警
IScanAlarmStrategy.notIntersect(newAlarms, oldAlarms, jobVo);
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.*;
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>, IScanAlarmStrategy {
@Resource
private LocationTurnoverRepository locationTurnoverRepository;
public MinPeopleNumberStrategy() {
Integer relevanceParam = RelevanceParamEnum.MIN_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) {
Result.no(Status.EXPECTATION_FAILED, "最大人数不能空或小于零");
}
}
//如果只设置星期没有设置时间,则默认时间是全天
for (TimeAndNumberParam item : timeAndNumber) {
for (TimeParam time : item.getTime()) {
if (time.getWeek() != null) {
if (time.getBeginTime() == null) {
time.setBeginTime("00:00:00");
}
if (time.getEndTime() == null) {
time.setEndTime("23:59:59");
}
}
}
}
//将时间和距离都设为-1
ruleParam.setDuration(null);
ruleParam.setDistance(null);
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;
StringBuilder begin = new StringBuilder();
StringBuilder end = new StringBuilder();
//筛选在当前时间生效的配置
for (TimeAndNumberParam item : timeAndNumberParamList) {
for (TimeParam time : item.getTime()) {
if (TimeUtil.judgeWeek(LocalDateTime.now(), time.getWeek())) {
if (TimeUtil.judgeTime(LocalDateTime.now(), time.getBeginTime(), time.getEndTime())) {
begin.append(time.getWeek()).append(" ").append(time.getBeginTime());
end.append(time.getWeek()).append(" ").append(time.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<>();
//查询员工’出‘这个围栏的进出信息
List<LocationTurnover> turnoverList = locationTurnoverRepository.withinFence(fenceId, false);
//筛选出在配置时间段内’出‘这个围栏的进出信息
turnoverList =
turnoverList
.stream()
.filter(e -> TimeUtil.judgeWeekTime(e.getTime(), begin.toString(), end.toString()))
.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).name(param.getFenceName()).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不重合的部分代表需要结束的报警
IScanAlarmStrategy.notIntersect(newAlarms, oldAlarms, jobVo);
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.*;
import com.yiring.app.util.TimeUtil;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.auth.domain.user.User;
import com.yiring.auth.domain.user.UserRepository;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import org.springframework.data.jpa.domain.Specification;
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;
@Resource
private UserRepository userRepository;
public NotAllowLeaveStrategy() {
Integer relevanceParam = RelevanceParamEnum.NOT_ALLOW_LEAVE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
ScanAlarmContext.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, "请至少配置一个不允许离开的人员");
}
}
//如果只设置星期没有设置时间,则默认时间是全天
for (TimeAndUserParam item : timeAndUser) {
for (TimeParam time : item.getTime()) {
if (time.getWeek() != null) {
if (time.getBeginTime() == null) {
time.setBeginTime("00:00:00");
}
if (time.getEndTime() == null) {
time.setEndTime("23:59:59");
}
}
}
}
//检查配置的员工是否存在
Specification<User> specification = (root, query, criteriaBuilder) -> {
CriteriaBuilder.In<Object> in = criteriaBuilder.in(root.get(User.Fields.uuid));
HashSet<String> ids = new HashSet<>();
for (TimeAndUserParam item : timeAndUser) {
for (RelevanceUserParam userParam : item.getUser()) {
ids.add(userParam.getUuid());
}
}
for (String uuid : ids) {
in.value(uuid);
}
return criteriaBuilder.and(in);
};
Map<String, List<User>> map = userRepository
.findAll(specification)
.stream()
.collect(Collectors.groupingBy(User::getUuid));
for (TimeAndUserParam item : timeAndUser) {
for (RelevanceUserParam userParam : item.getUser()) {
List<User> list = map.get(userParam.getUuid());
if (CollectionUtils.isEmpty(list)) {
return Result.no(Status.EXPECTATION_FAILED, "工号为:" + userParam.getUuid() + "员工不存在");
}
userParam.setRealName(list.get(0).getRealName());
}
}
ruleParam.setDuration(null);
ruleParam.setDistance(null);
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;
StringBuilder begin = new StringBuilder();
StringBuilder end = new StringBuilder();
//筛选在当前时间生效的配置
for (TimeAndUserParam item : timeAndUserParamList) {
for (TimeParam time : item.getTime()) {
if (TimeUtil.judgeWeek(LocalDateTime.now(), time.getWeek())) {
if (TimeUtil.judgeTime(LocalDateTime.now(), time.getBeginTime(), time.getEndTime())) {
timeAndUserParam = item;
begin.append(time.getWeek()).append(" ").append(time.getBeginTime());
end.append(time.getWeek()).append(" ").append(time.getEndTime());
break;
}
}
}
}
//如果不在配置的时间内,则将报警记录中的状态刷新为结束,并且需要添加的报警为空
if (timeAndUserParam == null) {
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
//筛选出在配置时间段内出这个围栏的进出信息
List<LocationTurnover> turnoverList = locationTurnoverRepository.withinFence(fenceId, false);
//筛选出在配置时间段内出这个围栏的进出信息
turnoverList =
turnoverList
.stream()
.filter(e -> TimeUtil.judgeTime(e.getTime(), begin.toString(), end.toString()))
.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).name(param.getFenceName()).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不重合的部分代表需要结束的报警
IScanAlarmStrategy.notIntersect(newAlarms, oldAlarms, jobVo);
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;
/**
* 滞留时长相关策略
* @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);
ScanAlarmContext.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(null);
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).name(param.getFenceName()).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不重合的部分代表需要结束的报警
IScanAlarmStrategy.notIntersect(newAlarms, oldAlarms, jobVo);
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 {
private 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.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.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 org.springframework.stereotype.Component;
/**
* 静止时长相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:32
*/
@Component
public class StaticDurationStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
public StaticDurationStrategy() {
Integer relevanceParam = RelevanceParamEnum.STATIC_DURATION.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
ScanAlarmContext.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(null);
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();
//筛选出围栏中静止的,并且静止时长超过配置规则时长的标签
LocalDateTime time = LocalDateTime.now().minusMinutes(rule.getDuration());
List<LocationFenceAlarm> newAlarms = tagSet
.stream()
.filter(LocationTag::getSilent)
.filter(e -> e.getTime().isBefore(time))
.map(e -> {
LocationFence fence = LocationFence.builder().id(fenceId).name(param.getFenceName()).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不重合的部分代表需要结束的报警
IScanAlarmStrategy.notIntersect(newAlarms, oldAlarms, jobVo);
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.LocationFence;
import com.yiring.app.domain.location.LocationFenceAlarm;
import com.yiring.app.domain.location.LocationTag;
import com.yiring.app.domain.location.LocationTagRepository;
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.locationtech.jts.geom.Geometry;
import org.springframework.stereotype.Component;
/**
* 触发报警距离相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:33
*/
@Component
public class TriggerAlarmDistanceStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
@Resource
private LocationTagRepository locationTagRepository;
public TriggerAlarmDistanceStrategy() {
Integer relevanceParam = RelevanceParamEnum.TRIGGER_ALARM_DISTANCE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
ScanAlarmContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
if (ruleParam.getDistance() == null || ruleParam.getDistance() < 0) {
return Result.no(Status.EXPECTATION_FAILED, "触发报警距离异常");
}
ruleParam.setDuration(null);
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();
Geometry geometry = param.getGeometry();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
//查询出距离围栏规则之类距离的所有标签,封装成报警信息
List<LocationTag> locationTags = locationTagRepository.findByDistance(geometry, rule.getDistance());
List<LocationFenceAlarm> newAlarms = locationTags
.stream()
.map(e -> {
LocationFence fence = LocationFence.builder().id(fenceId).name(param.getFenceName()).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不重合的部分代表需要结束的报警
IScanAlarmStrategy.notIntersect(newAlarms, oldAlarms, jobVo);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */ /* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.broadcast; package com.yiring.app.domain;
import com.yiring.common.domain.BasicEntity; import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
import lombok.*; import lombok.*;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants; import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment; import org.hibernate.annotations.Comment;
import org.hibernate.annotations.CreationTimestamp;
/** /**
* 播报音频 * 测试表
* *
* @author LJ-2204 * @author Jim
* @date 2022/5/7 * @version 0.1
* 2022/4/15 18:34
*/ */
@Getter @Getter
@Setter @Setter
@ToString @ToString
@SuperBuilder(toBuilder = true) @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@FieldNameConstants @FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
@Entity @Entity
@Table(name = "BS_BROADCAST_AUDIO") @TableName("TEST_TABLE")
@Comment("播报语音") @Table(name = "TEST_TABLE")
public class BroadcastAudio extends BasicEntity implements Serializable { @Comment("测试表")
public class TestTable implements Serializable {
@Serial @Serial
private static final long serialVersionUID = -7232247536987652847L; private static final long serialVersionUID = -6168070383092874608L;
@Comment("语音名称") @Comment("主键")
String name; @Id
String id;
@Comment("语音地址")
String uri;
@Comment("上传时间") @Comment("姓名")
@CreationTimestamp String name;
LocalDateTime uploadTime;
@Comment("备注") @Comment("年龄")
String describe; Integer age;
} }
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.alarm;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Objects;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Where;
import org.hibernate.snowflake.SnowflakeId;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/**
* @author tml
* @version 1.0
* @date 2022/4/27 11:20
*/
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@Entity
@Where(clause = "deleted = false")
@Table(name = "BS_Alarm_Type")
@Comment("报警类型信息")
@EntityListeners(AuditingEntityListener.class)
public class AlarmType implements Serializable {
@Serial
private static final long serialVersionUID = -735021155587741700L;
@Id
@Comment("主键id")
@GeneratedValue(generator = SnowflakeId.GENERATOR)
@GenericGenerator(name = SnowflakeId.GENERATOR, strategy = SnowflakeId.Strategy.LONG)
private Long id;
@Comment("报警类型名称")
private String name;
@Comment("围栏类型")
private Integer fenceType;
@Comment("关联参数类型")
private Integer relevanceParam;
@Comment("备注")
private String comment;
@Comment("创建时间")
@CreatedDate
@Column(nullable = false)
private LocalDateTime createTime;
@Comment("最后修改时间")
@LastModifiedDate
@Column(nullable = false)
private LocalDateTime lastUpdateTime;
@Comment(value = "是否删除")
@Column(nullable = false)
private Boolean deleted;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AlarmType alarmType = (AlarmType) o;
return (
Objects.equals(id, alarmType.id) &&
Objects.equals(name, alarmType.name) &&
Objects.equals(fenceType, alarmType.fenceType) &&
Objects.equals(relevanceParam, alarmType.relevanceParam) &&
Objects.equals(comment, alarmType.comment) &&
Objects.equals(createTime, alarmType.createTime) &&
Objects.equals(lastUpdateTime, alarmType.lastUpdateTime) &&
Objects.equals(deleted, alarmType.deleted)
);
}
@Override
public int hashCode() {
return Objects.hash(id, name, fenceType, relevanceParam, comment, createTime, lastUpdateTime, deleted);
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.alarm;
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.stereotype.Repository;
/**
* @author tml
* @version 1.0
* @date 2022/4/27 14:41
*/
@Repository
public interface AlarmTypeRepository
extends JpaRepository<AlarmType, Serializable>, JpaSpecificationExecutor<AlarmType> {
/**
* 查询名称是否存在
* @param name 名称
* @return true:存在 false:不存在
*/
Boolean existsByName(String name);
/**
* 根据名称查询
* @param name 名称
* @return 是否存在
*/
List<AlarmType> findAllByName(String name);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.appletUser;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import org.hibernate.annotations.Comment;
@Data
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Comment("小程序用户表")
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Table(name = "BS_APPLET_USER")
public class AppletUser implements Serializable {
@Serial
private static final long serialVersionUID = 5188008300684723724L;
@Id
@Comment("用户唯一标识")
String openid;
@Comment("用户电话")
String mobile;
@Comment("最后登录时间")
LocalDateTime LastLoginTime;
@Comment("创建时间")
LocalDateTime createTime;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.appletUser;
import java.io.Serializable;
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;
/**
* @author tzl
* 2022/4/22 13:55
*/
@Repository
public interface AppletUserRepository
extends JpaRepository<AppletUser, Serializable>, JpaSpecificationExecutor<AppletUser> {
@Query("SELECT COUNT(id) FROM AppletUser WHERE mobile=?1")
Integer countMobile(String mobile);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.broadcast;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;
import org.hibernate.snowflake.SnowflakeId;
import org.locationtech.jts.geom.Point;
/**
* @author tzl
* @version 1.0
* @description:
* @date 2022/5/5 17:06
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@Comment("播报设备表")
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Table(name = "BS_BROADCAST")
public class Broadcast implements Serializable {
@Serial
private static final long serialVersionUID = 2856845594409003209L;
@Comment("编号")
@Id
@GeneratedValue(generator = SnowflakeId.GENERATOR)
@GenericGenerator(name = SnowflakeId.GENERATOR, strategy = SnowflakeId.Strategy.LONG)
Long id;
@Comment("播报设备编号")
String broadcastNum;
@Comment("播报设备名称")
String broadcastName;
@Comment("坐标点信息")
@Column(columnDefinition = "geometry(Point,4326)")
Point point;
@Comment("播报设备地址")
String broadcastAdd;
@Comment("备注")
String remark;
@Comment("是否启用")
String status;
@Comment("创建时间")
@CreationTimestamp
LocalDateTime createTime;
@Comment("修改时间")
@UpdateTimestamp
LocalDateTime updateTime;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.broadcast;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* 播报音频
*
* @author LJ-2204
* @date 2022/5/7
*/
@Repository
public interface BroadcastAudioRepository
extends JpaRepository<BroadcastAudio, Serializable>, JpaSpecificationExecutor<BroadcastAudio> {}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.broadcast;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* @author tzl
* 2022/5/5 17:13
*/
@Repository
public interface BroadcastRepository
extends JpaRepository<Broadcast, Serializable>, JpaSpecificationExecutor<Broadcast> {}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.district;
import com.yiring.app.domain.location.LocationTag;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.Where;
import org.hibernate.snowflake.SnowflakeId;
import org.locationtech.jts.geom.Geometry;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/**
* @author tml
* @version 1.0
* @date 2022/4/26 11:44
*/
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@Entity
@Where(clause = "deleted = false")
@Table(name = "BS_District")
@Comment("区域信息")
@EntityListeners(AuditingEntityListener.class)
public class District implements Serializable {
@Serial
private static final long serialVersionUID = -1469002957843445743L;
@Id
@Comment("主键id")
@GeneratedValue(generator = SnowflakeId.GENERATOR)
@GenericGenerator(name = SnowflakeId.GENERATOR, strategy = SnowflakeId.Strategy.LONG)
private Long id;
@Comment("区域信息名称")
private String name;
@Comment("地图id")
private Integer mapId;
@Comment("风险等级")
private String riskGrade;
@Comment("消抖时间(秒)")
private Integer debouncingDuration;
@Comment("超时时间(秒)")
private Integer timeoutDuration;
@Comment("区域信息")
@Type(type = "jts_geometry")
@Column(columnDefinition = "geometry(Geometry,4326)")
private Geometry geometry;
@Comment("创建时间")
@CreatedDate
@Column(nullable = false)
private LocalDateTime createTime;
@Comment("最后修改时间")
@LastModifiedDate
@Column(nullable = false)
private LocalDateTime lastUpdateTime;
@Comment(value = "是否删除")
@Column(nullable = false)
Boolean deleted;
@ToString.Exclude
@Comment("区域中的标签集合")
@Builder.Default
@ManyToMany(fetch = FetchType.LAZY)
Set<LocationTag> tags = new HashSet<>(0);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.district;
import java.io.Serializable;
import java.util.List;
import org.locationtech.jts.geom.Geometry;
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;
/**
* @author tml
* @version 1.0
* @date 2022/4/26 13:59
*/
@Repository
public interface DistrictRepository extends JpaRepository<District, Serializable>, JpaSpecificationExecutor<District> {
/**
* 查询名称是否存在
* @param name 区域名称
* @return true:存在 false:不存在
*/
Boolean existsByName(String name);
/**
* 根据名称查询区域信息列表
* @param name 区域名称
* @return 区域列表
*/
List<District> findAllByName(String name);
/**
* 根据名称模糊查询区域信息
* @param name 名称
* @return 区域列表
*/
@Query("SELECT d FROM District d WHERE d.name like %?1%")
List<District> findLikeName(String name);
/**
* 查询空间信息在区域内的区域信息
* @param geometry 空间信息
* @return 区域信息
*/
@Query(value = "select d.* from bs_district d where st_contains(d.geometry, :geometry)", nativeQuery = true)
List<District> findByGeometryContains(Geometry geometry);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.icon;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;
import org.hibernate.snowflake.SnowflakeId;
/**
*
* @author tzl
* @version 1.0
* @description: 图标
* @date 2022/4/29 11:08
*/
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Table(name = "BS_ICON")
@Comment("图标")
public class Icon implements Serializable {
@Serial
private static final long serialVersionUID = 7848846860889883431L;
@Comment("编号")
@Id
@GeneratedValue(generator = SnowflakeId.GENERATOR)
@GenericGenerator(name = SnowflakeId.GENERATOR, strategy = SnowflakeId.Strategy.LONG)
Long id;
@Comment("图标名称")
String iconName;
@Comment("图标类型")
String iconType;
@Comment("图标分类")
String iconSort;
@Comment("在线图标")
String iconOnline;
@Comment("离线图标")
String iconOffline;
@Comment("创建时间")
@CreationTimestamp
LocalDateTime createTime;
@Comment("修改时间")
@UpdateTimestamp
LocalDateTime updateTime;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.icon;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* @author tzl
* 2022/4/29 13:49
*/
@Repository
public interface IconRepository extends JpaRepository<Icon, Serializable>, JpaSpecificationExecutor<Icon> {}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.key;
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.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
import org.locationtech.jts.geom.Point;
/**
*
*
* @author LJ-2204
* @date 2022/5/6
*/
@Getter
@Setter
@ToString
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Table(name = "BS_KEY_ALARM")
@Comment("按键报警")
public class KeyAlarm extends BasicEntity implements Serializable {
@Serial
private static final long serialVersionUID = -6050505164664867107L;
@Comment("地图 ID")
Long areaId;
@ManyToOne
@JoinColumn(name = "leader_id")
@JsonIgnore
@Comment("负责人")
User leader;
@Comment("标签编号")
String code;
@Comment("x")
BigDecimal x;
@Comment("y")
BigDecimal y;
@Comment("z")
BigDecimal z;
@Comment("坐标点信息")
Point point;
@Comment("报警状态")
Boolean enable;
@Builder.Default
@OneToMany(mappedBy = "keyAlarm")
@Comment("推送消息记录")
Set<KeyAlarmLog> rules = new HashSet<>(0);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.key;
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 javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
/**
* 报警规则推送记录
*
* @author LJ-2204
* @date 2022/5/12
*/
@Getter
@Setter
@ToString
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Table(name = "BS_KEY_ALARM_LOG")
@Comment("报警规则推送记录")
public class KeyAlarmLog extends BasicEntity implements Serializable {
@Serial
private static final long serialVersionUID = 5837910859908195485L;
@ManyToOne
@JoinColumn(name = "alarm_id")
@JsonIgnore
@Comment("按键报警")
KeyAlarm keyAlarm;
@Comment("通知方式")
String types;
@Comment("接收状态")
Boolean status;
@ManyToOne
@JoinColumn(name = "leader_id")
@JsonIgnore
@Comment("负责人")
User user;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.key;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
*
* @author LJ-2204
* @date 2022/5/6
*/
@Repository
public interface KeyAlarmLogRepository
extends JpaRepository<KeyAlarmLog, Serializable>, JpaSpecificationExecutor<KeyAlarmLog> {}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.key;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
*
* @author LJ-2204
* @date 2022/5/6
*/
@Repository
public interface KeyAlarmRepository extends JpaRepository<KeyAlarm, Serializable>, JpaSpecificationExecutor<KeyAlarm> {}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.key;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.yiring.auth.domain.dept.Department;
import com.yiring.auth.domain.user.User;
import com.yiring.common.domain.BasicEntity;
import java.io.Serial;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
/**
* 按键报警规则
*
* @author LJ-2204
* @date 2022/5/6
*/
@Getter
@Setter
@ToString
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Table(name = "BS_KEY_ALARM_RULES")
@Comment("按键报警规则")
public class KeyAlarmRule extends BasicEntity implements Serializable {
@Serial
private static final long serialVersionUID = -302167871277966250L;
@Comment("所属部门")
@OneToOne
@JsonIgnore
@JoinColumn(name = "department_id")
Department department;
@JsonIgnore
@Builder.Default
@Comment("用户集合")
@OneToMany
Set<User> users = new HashSet<>(0);
@Comment("推送类型")
String types;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.key;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
*
* @author LJ-2204
* @date 2022/5/6
*/
@Repository
public interface KeyAlarmRuleRepository
extends JpaRepository<KeyAlarmRule, Serializable>, JpaSpecificationExecutor<KeyAlarmRule> {}
/* (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;
}
/* (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> {}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.auth.domain.user.User;
import com.yiring.common.domain.BasicEntity;
import java.io.Serial;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.*;
import lombok.*;
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
* @version 1.0
* @date 2022/5/5 14:25
*/
@Getter
@Setter
@ToString
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@Where(clause = "deleted = false")
@Entity
@Table(name = "BS_LOCATION_ALARM_RULE")
@Comment("电子围栏的报警规则")
public class LocationAlarmRule extends BasicEntity implements Serializable {
@Serial
private static final long serialVersionUID = -2268859882881201793L;
@Comment("地图ID")
private Long mapId;
@Comment("地图名称")
private String mapName;
@Comment("电子围栏")
@ManyToOne
@JoinColumn(name = "fence_id")
private LocationFence locationFence;
@Comment("接收人集合")
@OneToMany
@ToString.Exclude
private Set<User> users;
@Comment("通知方式")
private String informManner;
@Comment("报警类型")
@ManyToMany
@ToString.Exclude
private Set<AlarmType> alarmTypes;
@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;
}
}
/* (C) 2022 YiRing, Inc. */
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;
/**
* @author tml
* @version 1.0
* @date 2022/5/5 15:13
*/
@Repository
public interface LocationAlarmRuleRepository
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);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import com.yiring.common.annotation.FieldMapping;
import com.yiring.common.domain.BasicEntity;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
import org.locationtech.jts.geom.Point;
/**
* 定位信标
* 引用:
* 1. 查询地图分区(定位系统), <a href="https://nl.yz-cloud.com/position/area/list">https://nl.yz-cloud.com/position/area/list</a>
* 2. 查询信标点(定位系统), <a href="https://nl.yz-cloud.com/position/config/point/list">https://nl.yz-cloud.com/position/config/point/list</a>
*
* @author Jim
* @version 0.1
* 2022/4/7 11:02
*/
@Getter
@Setter
@ToString
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Table(
name = "BS_LOCATION_BEACON",
indexes = { @Index(columnList = "linkId"), @Index(columnList = "code", unique = true) }
)
@Comment("定位信标")
public class LocationBeacon extends BasicEntity implements Serializable {
@Serial
private static final long serialVersionUID = 5419734189897829250L;
/**
* 数据来源于【真源人员定位系统 - 定位信标】
* 作用: 用于双向联动进行数据同步
*/
@FieldMapping("id")
@Comment("外链主键")
Long linkId;
@Comment("地图 ID")
Long areaId;
/**
* 前缀: BTI
* 后缀: 8 位数字
*/
@FieldMapping("deviceId")
@Comment("编号")
@Column(unique = true, nullable = false)
String code;
@Comment("x")
BigDecimal x;
@Comment("y")
BigDecimal y;
@Comment("z")
BigDecimal z;
@Comment("距离(米)")
Double distance;
@Comment("坐标点信息")
@Column(columnDefinition = "geometry(Point,4326)")
Point point;
@FieldMapping
@Comment("电量")
Integer volt;
@FieldMapping
@Comment("电量单位")
String voltUnit;
@Comment("状态更新时间")
LocalDateTime time;
@Comment("围栏集合")
@Builder.Default
@ManyToMany
@ToString.Exclude
Set<LocationFence> fences = new HashSet<>(0);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import java.io.Serializable;
import java.util.Set;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* @author Jim
* @version 0.1
* 2022/4/24 14:19
*/
@Repository
public interface LocationBeaconRepository
extends JpaRepository<LocationBeacon, Serializable>, JpaSpecificationExecutor<LocationBeacon> {
/**
* 根据编号集合查询
* @param codes 编号集合
* @return 查询结果
*/
Set<LocationBeacon> findByCodeIn(Set<String> codes);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import com.yiring.app.domain.video.Video;
import com.yiring.common.domain.BasicEntity;
import java.io.Serial;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.Where;
import org.locationtech.jts.geom.Geometry;
/**
* 围栏
* 引用: 定位平台接口规范V3.0.1 #7.1
*
* @author Jim
* @version 0.1
* 2022/4/7 16:26
*/
@Getter
@Setter
@ToString
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@Where(clause = "deleted = false")
@Entity
@Table(name = "BS_LOCATION_FENCE")
@Comment("围栏")
public class LocationFence extends BasicEntity implements Serializable {
@Serial
private static final long serialVersionUID = 4155868702188991300L;
@Comment("围栏名称")
private String name;
@Comment("地图ID")
private Long mapId;
@Comment("地图名称")
private String mapName;
@Comment("摄像头")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "video_id")
private Video video;
@Comment("围栏类别")
private Integer fenceType;
@Comment("空间信息")
@Type(type = "jts_geometry")
@Column(columnDefinition = "geometry(Geometry,4326)")
private Geometry geometry;
@Comment("滞留时间(秒)")
private Integer residenceTime;
@Comment("消抖时间(秒)")
private Integer threshold;
@Comment("是否启用")
private Boolean enable;
@Comment(value = "是否删除")
@Column(nullable = false)
Boolean deleted;
@Comment("信标集合")
@Builder.Default
@ManyToMany
@ToString.Exclude
private Set<LocationBeacon> beacons = new HashSet<>(0);
@Comment("围栏规则集合")
@Builder.Default
@OneToMany(mappedBy = "fence")
@ToString.Exclude
private Set<LocationFenceRule> rules = new HashSet<>(0);
@ToString.Exclude
@Comment("围栏中的标签集合")
@Builder.Default
@ManyToMany(fetch = FetchType.LAZY)
Set<LocationTag> tags = new HashSet<>(0);
@ToString.Exclude
@Comment("围栏中的报警记录集合")
@Builder.Default
@OneToMany(mappedBy = "fence")
Set<LocationFenceAlarm> fenceAlarms = new HashSet<>(0);
/*@SuppressWarnings({ "unused" })
public enum Mode {
NORMAL("常规区域"),
DANGER("危险源区域");
@Getter
final String text;
Mode(String text) {
this.text = text;
}
}*/
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import com.yiring.app.domain.alarm.AlarmType;
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 java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.locationtech.jts.geom.Point;
/**
* 围栏报警记录
*
* @author Jim
* @version 0.1
* 2022/5/12 21:33
*/
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Table(name = "BS_LOCATION_FENCE_ALARM")
@Comment("围栏报警记录")
public class LocationFenceAlarm extends BasicEntity implements Serializable {
@Serial
private static final long serialVersionUID = 2984248537199016912L;
@Comment("围栏")
@ManyToOne(fetch = FetchType.LAZY)
LocationFence fence;
@Comment("触警位置")
@Column(columnDefinition = "geometry(Point,4326)")
Point point;
@Comment("地图编号")
Long areaId;
@Comment("触警人员")
@ManyToOne(fetch = FetchType.LAZY)
User user;
@Comment("触警标签")
@ManyToOne(fetch = FetchType.LAZY)
LocationTag tag;
@Comment("报警开始时间")
LocalDateTime startTime;
@Comment("报警结束时间")
LocalDateTime endTime;
@Comment("报警类型")
@ManyToOne(fetch = FetchType.LAZY)
AlarmType type;
@Comment("状态")
@Enumerated(EnumType.STRING)
Status status;
@Builder.Default
@OneToMany(mappedBy = "fenceAlarm")
@Comment("推送记录")
List<FenceAlarmPushLog> pushLogs = new ArrayList<>();
@SuppressWarnings({ "unused" })
public enum Status {
ING("进行中"),
OVER("结束");
final String text;
Status(String text) {
this.text = text;
}
public String text() {
return this.text;
}
public static Status get(boolean flag) {
return flag ? ING : OVER;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LocationFenceAlarm that = (LocationFenceAlarm) o;
return (
Objects.equals(fence, that.fence) &&
Objects.equals(point, that.point) &&
Objects.equals(areaId, that.areaId) &&
Objects.equals(user, that.user) &&
Objects.equals(tag, that.tag) &&
Objects.equals(startTime, that.startTime) &&
Objects.equals(endTime, that.endTime) &&
Objects.equals(type, that.type) &&
status == that.status &&
Objects.equals(pushLogs, that.pushLogs)
);
}
@Override
public int hashCode() {
return Objects.hash(fence, point, areaId, user, tag, startTime, endTime, type, status, pushLogs);
}
}
/* (C) 2022 YiRing, Inc. */
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.data.repository.query.Param;
import org.springframework.stereotype.Repository;
/**
* @author Jim
* @version 0.1
* 2022/5/12 21:34
*/
@Repository
public interface LocationFenceAlarmRepository
extends JpaRepository<LocationFenceAlarm, Serializable>, JpaSpecificationExecutor<LocationFenceAlarm> {
/**
* 批量关闭报警状态
* @param ids id集
* @param now 当前时间
* @return 修改量
*/
@Query("UPDATE LocationFenceAlarm SET status = 'OVER', updateTime = :now, endTime = :now WHERE id IN(:ids)")
@Modifying
int batchOver(@Param("ids") List<Long> ids, @Param("now") LocalDateTime now);
/**
* 根据状态查询
* @param status 状态
* @return 报警信息
*/
@Query("SELECT l FROM LocationFenceAlarm l WHERE l.status = ?1")
List<LocationFenceAlarm> findAllByStatus(LocationFenceAlarm.Status status);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import org.locationtech.jts.geom.Geometry;
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.data.repository.query.Param;
import org.springframework.stereotype.Repository;
/**
* @author tml
* @version 1.0
* @date 2022/4/28 13:48
*/
@Repository
public interface LocationFenceRepository
extends JpaRepository<LocationFence, Serializable>, JpaSpecificationExecutor<LocationFence> {
/**
* 查询名称是否存在
* @param name 围栏名称
* @return true:存在 false:不存在
*/
Boolean existsByName(String name);
/**
* 根据名称查询围栏信息
* @param name 围栏名称
* @return 围栏信息
*/
List<LocationFence> findAllByName(String name);
/**
* 根据名称模糊查询围栏信息
* @param name 围栏名称
* @return 围栏信息
*/
@Query("SELECT f FROM LocationFence f WHERE f.name like %?1% AND f.deleted = false")
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 空间信息
* @return 围栏信息
*/
@Query(
value = "select f.* from bs_location_fence f where map_id = :areaId and st_contains(f.geometry, :geometry)",
nativeQuery = true
)
List<LocationFence> findByGeometryContains(Long areaId, Geometry geometry);
/**
* 批量启用或停用围栏
* @param ids 围栏id集
* @param enable true:启用 false:停用
* @param now 当前时间
* @return 修改了几条
*/
@Query(
value = "UPDATE LocationFence set enable = :enable, updateTime = :now WHERE id IN (:ids) AND deleted = false "
)
@Modifying
int batchEnable(@Param("ids") Set<Long> ids, @Param("enable") boolean enable, @Param("now") LocalDateTime now);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.common.domain.BasicEntity;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.Where;
/**
* 围栏规则
* TODO: 规则待梳理
*
* @author Jim
* @version 0.1
* 2022/4/7 18:25
*/
@Getter
@Setter
@ToString
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@Where(clause = "deleted = false")
@Entity
@Table(name = "BS_LOCATION_FENCE_RULE")
@Comment("围栏规则")
public class LocationFenceRule extends BasicEntity implements Serializable {
@Serial
private static final long serialVersionUID = -6683465582430417205L;
@Comment("围栏")
@ManyToOne
@JoinColumn(name = "fence_id")
private LocationFence fence;
@Comment("报警类别")
@ManyToOne
@JoinColumn(name = "alarm_id")
private AlarmType alarmType;
@Comment("关联参数类别")
private Integer relevanceParamType;
@Comment("规则,用json存入")
@Column(columnDefinition = "text")
private String rule;
@Comment(value = "是否删除")
@Column(nullable = false)
Boolean deleted;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
LocationFenceRule that = (LocationFenceRule) o;
return getId() != null && Objects.equals(getId(), that.getId());
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), fence, alarmType, relevanceParamType, rule, deleted);
}
}
/* (C) 2022 YiRing, Inc. */
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.stereotype.Repository;
/**
* @author tml
* @version 1.0
* 2022/4/29 11:40
*/
@Repository
public interface LocationFenceRuleRepository
extends JpaRepository<LocationFenceRule, Serializable>, JpaSpecificationExecutor<LocationFenceRule> {
/**
* 根据围栏id查询规则
* @param fence 围栏id
* @return 规则
*/
List<LocationFenceRule> findAllByFence(LocationFence fence);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
import com.yiring.auth.domain.user.User;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.locationtech.jts.geom.Point;
/**
* 定位数据
* 引用: 定位平台接口规范V3.0.1 #6
* TODO:
* 1. 实时数据日志的存储结构 TimeScale: 时间粒度,每天一个分区
* eg: SELECT create_hypertable('BS_LOCATION_LOG', 'time', chunk_time_interval => INTERVAL '1 day')
*
* @author Jim
* @version 0.1
* 2022/4/7 10:21
*/
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
@Table(name = "BS_LOCATION_LOG", indexes = { @Index(name = "idx_time", columnList = "time") })
@Comment("定位数据")
public class LocationLog implements Serializable {
@Serial
private static final long serialVersionUID = 3467455881020691989L;
@Comment("定位标签时序复合主键")
@EmbeddedId
TagTimeId id;
@Comment("地图 ID")
Long areaId;
@Comment("楼层")
String floor;
/**
* 来源于定位数据产生时刻标签所属的人员
*/
@Comment("用户")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
User user;
/**
* 来源于定位标签定位时刻的人员状态
*/
@Comment("用户状态")
User.Status status;
@Comment("坐标点信息")
@Column(columnDefinition = "geometry(Point,4326)")
Point point;
@Comment("信标集合")
@Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
JSONArray beacons;
@Comment("围栏集合")
@Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
JSONArray fences;
@Comment("区域集合")
@Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
JSONArray districts;
@Comment("静止/运动")
Boolean silent;
@Comment("电量")
Integer volt;
@Comment("电量单位")
String voltUnit;
@Comment("是否在厂区外")
Boolean out;
@Comment("原始数据")
@Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
JSONObject raw;
@Comment("定位时间")
LocalDateTime locationTime;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* @author Jim
* @version 0.1
* 2022/4/24 18:03
*/
@Repository
public interface LocationLogRepository
extends JpaRepository<LocationLog, TagTimeId>, JpaSpecificationExecutor<LocationLog> {}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import cn.hutool.core.util.StrUtil;
import com.yiring.app.domain.visitor.Car;
import com.yiring.auth.domain.user.User;
import com.yiring.common.annotation.FieldMapping;
import com.yiring.common.domain.BasicEntity;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Objects;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
import org.locationtech.jts.geom.Point;
/**
* 定位标签
* 引用:
* 1. 定位平台接口规范V3.0.1 #4.3
* 2. 真源定位系统后台管理模块
*
* @author Jim
* @version 0.1
* 2022/4/7 11:02
*/
@Getter
@Setter
@ToString
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Table(
name = "BS_LOCATION_TAG",
indexes = {
@Index(columnList = "linkId"),
@Index(columnList = "type"),
@Index(columnList = "used"),
@Index(columnList = "user_id"),
@Index(columnList = "code", unique = true),
}
)
@Comment("定位标签")
public class LocationTag extends BasicEntity implements Serializable {
@Serial
private static final long serialVersionUID = 5419734189897829250L;
/**
* 数据来源于【真源人员定位系统 - 定位标签】
* 作用: 用于双向联动进行数据同步
*/
@FieldMapping("id")
@Comment("外链主键")
Long linkId;
@FieldMapping
@Comment("IMEI 设备标识码")
String imei;
/**
* 前缀: BTT
* 后缀: 8 位数字
*/
@FieldMapping("tagId")
@Comment("编号")
@Column(unique = true, nullable = false)
String code;
@FieldMapping("tagCode")
@Comment("型号")
@Enumerated(EnumType.STRING)
Type type;
@FieldMapping
@Comment("静止/运动")
Boolean silent;
@OneToOne
@Comment("绑定用户")
User user;
@OneToOne
@Comment("绑定车辆")
Car car;
@FieldMapping
@Comment("使用/闲置")
Boolean used;
@FieldMapping
@Comment("电量")
Integer volt;
@FieldMapping
@Comment("电量单位")
String voltUnit;
@FieldMapping
@Comment("类型(1:内部/2:访客)")
Integer category;
@Comment("最新定位坐标")
@Column(columnDefinition = "geometry(Point,4326)")
Point point;
@Comment("是否在厂外")
Boolean out;
@Comment("静止/运动变更时间")
LocalDateTime time;
@SuppressWarnings({ "unused" })
public enum Type {
BTT01("蓝牙人员定位卡"),
BTT02("蓝牙车辆定位器");
final String text;
Type(String text) {
this.text = text;
}
public String text() {
return this.text;
}
public static Type getByCode(String text) {
for (Type type : values()) {
if (StrUtil.equals(type.text(), text)) {
return type;
}
}
throw new RuntimeException("Type获取未知风险");
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LocationTag that = (LocationTag) o;
return (
Objects.equals(linkId, that.linkId) &&
Objects.equals(imei, that.imei) &&
Objects.equals(code, that.code) &&
type == that.type &&
Objects.equals(silent, that.silent) &&
Objects.equals(user, that.user) &&
Objects.equals(used, that.used) &&
Objects.equals(volt, that.volt) &&
Objects.equals(voltUnit, that.voltUnit) &&
Objects.equals(category, that.category) &&
Objects.equals(point, that.point) &&
Objects.equals(out, that.out) &&
Objects.equals(time, that.time)
);
}
@Override
public int hashCode() {
return Objects.hash(linkId, imei, code, type, silent, user, used, volt, voltUnit, category, point, out, time);
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import java.io.Serializable;
import java.util.List;
import org.locationtech.jts.geom.Geometry;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
/**
* 定位标签JPA
* @author LJ-2204
* 2022/4/14
*/
@Repository
public interface LocationTagRepository
extends JpaRepository<LocationTag, Serializable>, JpaSpecificationExecutor<LocationTag> {
LocationTag findByCode(String code);
/**
* 查询在指定区域内的所有标签
* @param geometry 指定区域
* @return 标签
*/
@Query(value = "SELECT * FROM BS_LOCATION_TAG bl WHERE ST_Contains(?1, bl.point)", nativeQuery = true)
List<LocationTag> findInArea(Geometry geometry);
/**
* 查询在指定区域内的所有标签数量
* @param geometry 指定区域
* @return 标签数量
*/
@Query(value = "SELECT count(*) FROM BS_LOCATION_TAG bl WHERE ST_Contains(?1, bl.point)", nativeQuery = true)
int findInAreaNum(Geometry geometry);
/**
* 根据多个员工id查询定位标签
* @param userIds 员工id集
* @return 定位标签
*/
@Query(value = "SELECT * FROM BS_LOCATION_TAG WHERE user_id IN (?1)", nativeQuery = true)
List<LocationTag> findByUserIds(List<Long> userIds);
/**
* 查询距离指定区域多少米的标签
* @param geometry 指定区域
* @param distance 距离(米)
* @return 定位标签
*/
@Query(value = "SELECT * FROM BS_LOCATION_TAG WHERE st_distance(point, :geometry) < :distance", nativeQuery = true)
List<LocationTag> findByDistance(@Param("geometry") Geometry geometry, @Param("distance") Integer distance);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
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.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.TypeDef;
/**
* 定位进出记录
*
* @author Jim
* @version 0.1
* 2022/5/12 17:54
*/
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
@Table(name = "BS_LOCATION_TURNOVER", indexes = { @Index(columnList = "type"), @Index(columnList = "sourceId") })
@Comment("定位进出记录")
public class LocationTurnover extends BasicEntity implements Serializable {
@Serial
private static final long serialVersionUID = 887764448464587364L;
@Comment("进出区域/围栏表主键")
Long sourceId;
@Comment("类型")
@Enumerated(EnumType.STRING)
Type type;
@Comment("定位标签")
@ManyToOne(fetch = FetchType.LAZY)
LocationTag tag;
@Comment("定位时间")
LocalDateTime time;
@Comment("用户")
@ManyToOne(fetch = FetchType.LAZY)
User user;
@Comment("进入")
Boolean enter;
@Comment("是否为最新状态")
Boolean isLatest;
@SuppressWarnings({ "unused" })
public enum Type {
FENCE("围栏"),
DISTRICT("区域");
final String text;
Type(String text) {
this.text = text;
}
public String text() {
return this.text;
}
}
}
/* (C) 2022 YiRing, Inc. */
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;
/**
* @author Jim
* @version 0.1
* 2022/5/12 18:13
*/
@Repository
public interface LocationTurnoverRepository
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.domain.location;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.FetchType;
import javax.persistence.OneToOne;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
/**
* 定位标签时序联合主键
* @author Jim
* @version 0.1
* 2022/5/10 10:24
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Embeddable
public class TagTimeId implements Serializable {
@Serial
private static final long serialVersionUID = -5254861902659471641L;
@Comment("定位标签")
@OneToOne(fetch = FetchType.LAZY)
LocationTag tag;
@Comment("定位时间")
@Column(nullable = false, columnDefinition = "timestamp without time zone")
LocalDateTime time;
public TagTimeId(LocationTag tag) {
this.tag = tag;
this.time = LocalDateTime.now();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.log;
import com.alibaba.fastjson.JSONObject;
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
/**
* 真源定位系统实时数据日志
* TODO:
* 1. 实时数据日志的存储结构 TimeScale: 时间粒度,每小时一个分区
* eg: SELECT create_hypertable('ZY_REALTIME_LOG', 'time', chunk_time_interval => INTERVAL '1 hour')
* 2. 数据分区压缩
* 3. 定时删除过期分区数据
* 参考:<a href="https://blog.csdn.net/yang_z_1/article/details/111560747">文档</a>
*
* @author Jim
* @version 0.1
* 2022/4/25 15:52
*/
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
@Table(name = "ZY_REALTIME_LOG", indexes = { @Index(columnList = "method") })
@Comment("真源定位系统实时数据日志")
public class ZyRealtimeLog implements Serializable {
@Serial
private static final long serialVersionUID = 5545864821082386L;
@Comment("时间")
@Id
@GeneratedValue(generator = "time-id")
@GenericGenerator(name = "time-id", strategy = "com.yiring.app.util.TimeIdGenerator")
@Column(nullable = false, columnDefinition = "timestamp without time zone")
LocalDateTime time;
@Comment("类型")
@Column(nullable = false)
String method;
@Comment("内容")
@Type(type = "jsonb")
@Column(nullable = false, columnDefinition = "jsonb")
JSONObject raw;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.log;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author Jim
* @version 0.1
* 2022/4/25 16:02
*/
public interface ZyRealtimeLogRepository extends JpaRepository<ZyRealtimeLog, Serializable> {}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.perstatistics;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;
import org.hibernate.snowflake.SnowflakeId;
/**
* @author tzl
* @version 1.0
* @description:
* @date 2022/5/15 9:15
*/
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Table(name = "BS_PERSONNEL_STATISTICS")
@Comment("区域人员统计")
public class PersonnelStatistics implements Serializable {
@Serial
private static final long serialVersionUID = 1276138943241366605L;
@Id
@Comment("主键id")
@GeneratedValue(generator = SnowflakeId.GENERATOR)
@GenericGenerator(name = SnowflakeId.GENERATOR, strategy = SnowflakeId.Strategy.LONG)
Long id;
@Comment("区域")
String region;
@Comment("入场人数")
String admissionNumber;
@Comment("出场人数")
String attendance;
@Comment("创建时间")
@CreationTimestamp
LocalDateTime createTime;
@Comment("修改时间")
@UpdateTimestamp
LocalDateTime updateTime;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.perstatistics;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* @author tzl
* @version 1.0
* @description:
* @date 2022/5/15 9:20
*/
@Repository
public interface PersonnelStatisticsRepository
extends JpaRepository<PersonnelStatistics, Serializable>, JpaSpecificationExecutor<PersonnelStatistics> {}
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论