Ver Fonte

+ 园区监测

chen.cheng há 7 meses atrás
pai
commit
3a21bff84d
57 ficheiros alterados com 5159 adições e 0 exclusões
  1. 44 0
      bd-park/park-backend/.gitignore
  2. 58 0
      bd-park/park-backend/README.md
  3. 23 0
      bd-park/park-backend/park-application/Dockerfile
  4. 13 0
      bd-park/park-backend/park-application/build.xml
  5. 104 0
      bd-park/park-backend/park-application/deploy.sh
  6. 134 0
      bd-park/park-backend/park-application/pom.xml
  7. 22 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/BDApplication.java
  8. 18 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/RuoYiServletInitializer.java
  9. 111 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/bd/socket/FenceVioEvtSocketServer.java
  10. 110 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/bd/socket/PointWebSocketServer.java
  11. 17 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/common/BDConst.java
  12. 21 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/common/enums/EvtStatus.java
  13. 21 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/common/enums/EvtType.java
  14. 120 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/engine/EvtFusionEngine.java
  15. 30 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/engine/IFusionEngine.java
  16. 79 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/engine/LocationInfo.java
  17. 149 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/engine/impl/FenceBreakInEngine.java
  18. 100 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/engine/impl/PointFusionEngine.java
  19. 31 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/mqtt/UWBLocationListener.java
  20. 50 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/mqtt/UWBLocationSubscribeListener.java
  21. 112 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/web/controller/bd/BdDevcTrailUwbController.java
  22. 96 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/web/controller/bd/BdFenceInfoController.java
  23. 95 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/web/controller/bd/BdFenceVioEvtController.java
  24. 20 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/web/core/config/MqttCfg.java
  25. 125 0
      bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/web/core/config/SwaggerConfig.java
  26. 1 0
      bd-park/park-backend/park-application/src/main/resources/META-INF/spring-devtools.properties
  27. 104 0
      bd-park/park-backend/park-application/src/main/resources/application-druid.yml
  28. 105 0
      bd-park/park-backend/park-application/src/main/resources/application-hm.yml
  29. 108 0
      bd-park/park-backend/park-application/src/main/resources/application-k8s.yml
  30. 104 0
      bd-park/park-backend/park-application/src/main/resources/application-prod.yml
  31. 125 0
      bd-park/park-backend/park-application/src/main/resources/application.yml
  32. 2 0
      bd-park/park-backend/park-application/src/main/resources/banner.txt
  33. 38 0
      bd-park/park-backend/park-application/src/main/resources/i18n/messages.properties
  34. 93 0
      bd-park/park-backend/park-application/src/main/resources/logback.xml
  35. 20 0
      bd-park/park-backend/park-application/src/main/resources/mybatis/mybatis-config.xml
  36. 1 0
      bd-park/park-backend/park-application/version
  37. 137 0
      bd-park/park-backend/park-common/pom.xml
  38. 665 0
      bd-park/park-backend/park-common/src/main/java/com/huashe/park/application/common/DateTimeUtil.java
  39. 67 0
      bd-park/park-backend/park-common/src/main/java/com/huashe/park/application/common/geo/CoordinateConverter.java
  40. 193 0
      bd-park/park-backend/park-common/src/main/java/com/huashe/park/application/common/geo/GeoUtils.java
  41. 84 0
      bd-park/park-backend/park-core/pom.xml
  42. 135 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/domain/BdDevcTrailUwb.java
  43. 107 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/domain/BdFenceInfo.java
  44. 146 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/domain/BdFenceVioEvt.java
  45. 61 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/mapper/BdDevcTrailUwbMapper.java
  46. 62 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/mapper/BdFenceInfoMapper.java
  47. 62 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/mapper/BdFenceVioEvtMapper.java
  48. 62 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/IBdDevcTrailUwbService.java
  49. 62 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/IBdFenceInfoService.java
  50. 62 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/IBdFenceVioEvtService.java
  51. 97 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/impl/BdDevcTrailUwbServiceImpl.java
  52. 98 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/impl/BdFenceInfoServiceImpl.java
  53. 97 0
      bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/impl/BdFenceVioEvtServiceImpl.java
  54. 97 0
      bd-park/park-backend/park-core/src/main/resources/mapper/bd/BdDevcTrailUwbMapper.xml
  55. 84 0
      bd-park/park-backend/park-core/src/main/resources/mapper/bd/BdFenceInfoMapper.xml
  56. 118 0
      bd-park/park-backend/park-core/src/main/resources/mapper/bd/BdFenceVioEvtMapper.xml
  57. 259 0
      bd-park/park-backend/pom.xml

+ 44 - 0
bd-park/park-backend/.gitignore

@@ -0,0 +1,44 @@
+# Intellij project files
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# Maven
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+
+# Eclipse
+.metadata/
+.settings/
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+.project
+.classpath
+.loadpath

+ 58 - 0
bd-park/park-backend/README.md

@@ -0,0 +1,58 @@
+
+<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.6.4</h1>
+<h4 align="center">基于 Vue/Element UI 和 Spring Boot/Spring Cloud & Alibaba 前后端分离的分布式微服务架构</h4>
+
+
+## 平台简介
+
+能源管理平台
+
+* 采用前后端分离的模式,微服务版本前端(基于 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue))。
+* 后端采用Spring Boot、Spring Cloud & Alibaba。
+* 注册中心、配置中心选型Nacos,权限认证使用Redis。
+* 流量控制框架选型Sentinel,分布式事务选型Seata。
+* 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Cloud-Vue3](https://github.com/yangzongzhuan/RuoYi-Cloud-Vue3),保持同步更新。
+
+## 系统模块
+
+~~~
+com.ruoyi     
+├── nrg-modules         // 能源业务模块
+│       └── ruoyi-system                              // 系统模块 [9201]
+│       └── ems-server                                // 能源管理服务 [9202]
+├── ruoyi-ui              // 前端框架 [80]
+├── ruoyi-gateway         // 网关模块 [9100]
+├── ruoyi-auth            // 认证中心 [9200]
+├── ruoyi-api             // 接口模块
+│       └── ruoyi-api-system                          // 系统接口
+├── ruoyi-common          // 通用模块
+│       └── ruoyi-common-core                         // 核心模块
+│       └── ruoyi-common-datascope                    // 权限范围
+│       └── ruoyi-common-datasource                   // 多数据源
+│       └── ruoyi-common-log                          // 日志记录
+│       └── ruoyi-common-redis                        // 缓存服务
+│       └── ruoyi-common-seata                        // 分布式事务
+│       └── ruoyi-common-security                     // 安全模块
+│       └── ruoyi-common-swagger                      // 系统接口
+├──pom.xml                // 公共依赖
+~~~
+
+## 内置功能
+
+1.  用户管理:用户是系统操作者,该功能主要完成系统用户配置。
+2.  部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
+3.  岗位管理:配置系统用户所属担任职务。
+4.  菜单管理:配置系统菜单,操作权限,按钮权限标识等。
+5.  角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
+6.  字典管理:对系统中经常使用的一些较为固定的数据进行维护。
+7.  参数管理:对系统动态配置常用参数。
+8.  通知公告:系统通知公告信息发布维护。
+9.  操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
+10. 登录日志:系统登录日志记录查询包含登录异常。
+11. 在线用户:当前系统中活跃用户状态监控。
+12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
+13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。
+14. 系统接口:根据业务代码自动生成相关的api接口文档。
+15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
+16. 在线构建器:拖动表单元素生成相应的HTML代码。
+17. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。

+ 23 - 0
bd-park/park-backend/park-application/Dockerfile

@@ -0,0 +1,23 @@
+# 使用官方的 OpenJDK 8 镜像作为基础镜像
+FROM openjdk:8-jdk-alpine
+# author
+MAINTAINER hs-bd
+
+# 创建存放上传文件的目录
+RUN mkdir -p /opt/project/ruoyi/ruoyi-backend/upload-file-path
+# 创建存放日志的目录
+RUN mkdir -p /opt/project/ruoyi/ruoyi-backend/logs
+# 安装字体文件
+RUN mkdir -p /etc/apk/
+RUN touch /etc/apk/repositories
+RUN echo -e 'https://mirrors.aliyun.com/alpine/v3.6/main/\nhttps://mirrors.aliyun.com/alpine/v3.6/community/' > /etc/apk/repositories
+RUN set -xe && apk --no-cache add ttf-dejavu fontconfig
+
+# 设置工作目录
+WORKDIR /opt/project/ruoyi/ruoyi-backend
+# 将构建好的 JAR 文件复制到容器中
+COPY ./target/bd-location.jar bd-location.jar
+# 暴露应用程序端口
+EXPOSE 8080
+# 启动应用程序
+CMD ["nohup","java","-jar","/opt/project/ruoyi/ruoyi-backend/bd-location.jar", "--spring.profiles.active=k8s" , ">", "/dev/null","2>&1" ,"&"]

+ 13 - 0
bd-park/park-backend/park-application/build.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="bd-location" basedir=".">
+    <property environment="SystemVariable"/>
+    <property name="buildName" value="bd-location"/>
+    <!--默认目标-->
+    <target name="Build" depends="copy-out"/>
+    <!--所有的打包最终需要文件copy到特定目录,方便jenkins上取包-->
+    <target name="copy-out">
+        <copy todir="${basedir}/../out" overwrite="true" failonerror="no">
+            <fileset file="${basedir}/target/${buildName}.jar"/>
+        </copy>
+    </target>
+</project>

+ 104 - 0
bd-park/park-backend/park-application/deploy.sh

@@ -0,0 +1,104 @@
+#!/bin/bash
+
+# 设置变量
+PROJECT_NAME="bd-app-backend"
+DOCKER_IMAGE_NAME="bd-app-backend"
+REMOTE_REGISTRY=${REMOTE_REGISTRY:-"docker.xt.wenhq.top:8083/bd"}
+VERSION_FILE="version"
+LOG_FILE="deploy.log"
+
+# 日志函数
+log() {
+  echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
+}
+
+# 读取当前版本号
+CURRENT_VERSION=$(cat $VERSION_FILE)
+if [ -z "$CURRENT_VERSION" ]; then
+  CURRENT_VERSION="0.0"
+fi
+
+# 分离大版本号和小版本号
+CURRENT_MAJOR=$(echo $CURRENT_VERSION | cut -d'.' -f1)
+CURRENT_MINOR=$(echo $CURRENT_VERSION | cut -d'.' -f2)
+
+# 用户选择是否修改大版本号
+read -p "是否修改大版本号?(a/i/ne): " modify_major_version
+
+if [ "$modify_major_version" == "a" ]; then
+  CURRENT_MAJOR=$((CURRENT_MAJOR + 1))
+  CURRENT_MINOR=0  # 重置小版本号
+elif [ "$modify_major_version" == "i" ]; then
+  CURRENT_MINOR=$((CURRENT_MINOR + 1))  # 增加小版本号
+else
+  echo "跳过版本号修改"
+fi
+
+# 更新版本号
+NEXT_VERSION="${CURRENT_MAJOR}.${CURRENT_MINOR}"
+echo $NEXT_VERSION > $VERSION_FILE
+echo "版本号:" $NEXT_VERSION
+# 用户选择执行的步骤
+echo "请选择要执行的步骤(输入数字):"
+echo "1. 编译bd-app-backend项目"
+echo "2. 构建Docker镜像"
+echo "3. 推送Docker镜像到远程仓库"
+echo "4. 执行所有步骤"
+read -p "请输入选项(1/2/3/4): " choice
+
+# 编译项目
+compile_project() {
+  log "开始编译bd-app-backend项目..."
+  mvn clean install
+  if [ $? -ne 0 ]; then
+    log "bd-app-backend项目编译失败。退出脚本。"
+    exit 1
+  fi
+  log "bd-app-backend项目编译完成"
+}
+
+# 构建Docker镜像
+build_docker_image() {
+  log "开始构建Docker镜像..."
+  docker build -t ${REMOTE_REGISTRY}/${DOCKER_IMAGE_NAME}:v${NEXT_VERSION} .
+  if [ $? -ne 0 ]; then
+    log "Docker镜像构建失败。退出脚本。"
+    exit 1
+  fi
+  log "Docker镜像构建完成"
+}
+
+# 推送Docker镜像到远程仓库
+push_docker_image() {
+  log "开始推送Docker镜像到远程仓库..."
+  docker push ${REMOTE_REGISTRY}/${DOCKER_IMAGE_NAME}:v${NEXT_VERSION}
+  if [ $? -ne 0 ]; then
+    log "Docker镜像推送失败。退出脚本。"
+    exit 1
+  fi
+  log "Docker镜像推送完成"
+}
+
+# 根据用户选择执行相应的步骤
+case $choice in
+  1)
+    compile_project
+    ;;
+  2)
+    build_docker_image
+    ;;
+  3)
+    push_docker_image
+    ;;
+  4)
+    compile_project
+    build_docker_image
+    push_docker_image
+    ;;
+  *)
+    log "无效的选项。退出脚本。"
+    exit 1
+    ;;
+esac
+
+log "所有任务完成"

+ 134 - 0
bd-park/park-backend/park-application/pom.xml

@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.huashe</groupId>
+        <artifactId>bd-park</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.huashe.bd-park</groupId>
+    <artifactId>park-appliication</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <description>
+        park-appliication核心模块
+    </description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <!-- spring-boot-devtools -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional> <!-- 表示依赖不会传递 -->
+        </dependency>
+
+        <!-- swagger3-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 防止进入swagger页面报类型转换错误,排除3.0.0中的引用,手动增加1.6.2版本 -->
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.6.2</version>
+        </dependency>
+
+        <!-- Mysql驱动包 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.huashe.application</groupId>
+            <artifactId>ruoyi-framework</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.dtflys.forest</groupId>
+            <artifactId>forest-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>net.dreamlu</groupId>
+            <artifactId>mica-mqtt-client-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.huashe</groupId>
+            <artifactId>park-common</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.huashe.park.application.bd-park</groupId>
+            <artifactId>park-core</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.5.15</version>
+                <configuration>
+                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.1.0</version>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>
+            </plugin>
+            <!--The configuration of maven-antrun-plugin 打zip包-->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <id>package</id>
+                        <phase>package</phase>
+                        <configuration>
+                            <target>
+                                <ant antfile="build.xml">
+                                    <target name="Build"/>
+                                </ant>
+                            </target>
+                        </configuration>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 22 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/BDApplication.java

@@ -0,0 +1,22 @@
+package com.huashe.park.application;
+
+import com.dtflys.forest.springboot.annotation.ForestScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+
+/**
+ * 启动程序
+ *
+ * @author ruoyi
+ */
+@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+@ForestScan(basePackages = "com.ruoyi.system.rest")
+public class BDApplication
+{
+    public static void main(String[] args)
+    {
+        // System.setProperty("spring.devtools.restart.enabled", "false");
+        SpringApplication.run(BDApplication.class, args);
+    }
+}

+ 18 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/RuoYiServletInitializer.java

@@ -0,0 +1,18 @@
+package com.huashe.park.application;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+/**
+ * web容器中进行部署
+ *
+ * @author ruoyi
+ */
+public class RuoYiServletInitializer extends SpringBootServletInitializer
+{
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
+    {
+        return application.sources(BDApplication.class);
+    }
+}

+ 111 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/bd/socket/FenceVioEvtSocketServer.java

@@ -0,0 +1,111 @@
+package com.huashe.park.application.bd.socket;
+
+import com.alibaba.fastjson2.JSON;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.CrossOrigin;
+
+import javax.annotation.PostConstruct;
+import javax.websocket.OnClose;
+import javax.websocket.OnError;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.PathParam;
+import javax.websocket.server.ServerEndpoint;
+import java.io.IOException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@ServerEndpoint("/ws/evt/{device}")
+@CrossOrigin(origins = "*")
+@Component
+public class FenceVioEvtSocketServer {
+    private static final Logger logger = LoggerFactory.getLogger(FenceVioEvtSocketServer.class);
+    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
+    private static AtomicInteger onlineNum = new AtomicInteger();
+    //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
+    private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();
+
+    @PostConstruct
+    public void init() {
+        logger.info("WebSocketServer init");
+    }
+
+    //发送消息
+    public void sendMessage(Session session, String message) throws IOException {
+        if (session != null) {
+            synchronized (session) {
+                logger.info("发送数据:{}", message);
+                session.getBasicRemote().sendText(message);
+            }
+        }
+    }
+
+    //给指定用户发送信息
+    public void sendInfo(String userName, String message) {
+        Session session = sessionPools.get(userName);
+        if (session == null) return;
+        try {
+            sendMessage(session, message);
+        } catch (Exception e) {
+            logger.info("server get {}", e.getMessage());
+        }
+    }
+
+    // 群发消息
+    public void broadcast(Object message) {
+        for (Session session : sessionPools.values()) {
+            try {
+                sendMessage(session, JSON.toJSONString(message));
+            } catch (Exception e) {
+                logger.info("server get {}", e.getMessage());
+            }
+        }
+    }
+
+    //建立连接成功调用
+    @OnOpen
+    public void onOpen(Session session, @PathParam(value = "device") String device) {
+        sessionPools.put(device, session);
+        addOnlineCount();
+    }
+
+    //关闭连接时调用
+    @OnClose
+    public void onClose(@PathParam(value = "device") String device) {
+        sessionPools.remove(device);
+        subOnlineCount();
+        logger.info("{}断开webSocket连接!当前人数为:{}", device, onlineNum);
+    }
+
+    //收到客户端信息后,根据接收人的username把消息推下去或者群发
+    // to=-1群发消息
+    @OnMessage
+    public void onMessage(String message) throws IOException {
+        logger.info("server get {}", message);
+    }
+
+    //错误时调用
+    @OnError
+    public void onError(Session session, Throwable throwable) {
+        logger.info("server get {}", throwable.getMessage());
+    }
+
+    public static void addOnlineCount() {
+        onlineNum.incrementAndGet();
+    }
+
+    public static void subOnlineCount() {
+        onlineNum.decrementAndGet();
+    }
+
+    public static AtomicInteger getOnlineNumber() {
+        return onlineNum;
+    }
+
+    public static ConcurrentHashMap<String, Session> getSessionPools() {
+        return sessionPools;
+    }
+}

+ 110 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/bd/socket/PointWebSocketServer.java

@@ -0,0 +1,110 @@
+package com.huashe.park.application.bd.socket;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.CrossOrigin;
+
+import javax.annotation.PostConstruct;
+import javax.websocket.OnClose;
+import javax.websocket.OnError;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.PathParam;
+import javax.websocket.server.ServerEndpoint;
+import java.io.IOException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@ServerEndpoint("/ws/point/{device}")
+@CrossOrigin(origins = "*")
+@Component
+public class PointWebSocketServer {
+    private static final Logger logger = LoggerFactory.getLogger(PointWebSocketServer.class);
+    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
+    private static AtomicInteger onlineNum = new AtomicInteger();
+    //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
+    private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();
+
+    @PostConstruct
+    public void init() {
+        logger.info("WebSocketServer init");
+    }
+
+    //发送消息
+    public void sendMessage(Session session, String message) throws IOException {
+        if (session != null) {
+            synchronized (session) {
+                logger.info("发送数据:{}", message);
+                session.getBasicRemote().sendText(message);
+            }
+        }
+    }
+
+    //给指定用户发送信息
+    public void sendInfo(String userName, String message) {
+        Session session = sessionPools.get(userName);
+        if (session == null) return;
+        try {
+            sendMessage(session, message);
+        } catch (Exception e) {
+            logger.info("server get {}", e.getMessage());
+        }
+    }
+
+    // 群发消息
+    public void broadcast(String message) {
+        for (Session session : sessionPools.values()) {
+            try {
+                sendMessage(session, message);
+            } catch (Exception e) {
+                logger.info("server get {}", e.getMessage());
+            }
+        }
+    }
+
+    //建立连接成功调用
+    @OnOpen
+    public void onOpen(Session session, @PathParam(value = "device") String device) {
+        sessionPools.put(device, session);
+        addOnlineCount();
+    }
+
+    //关闭连接时调用
+    @OnClose
+    public void onClose(@PathParam(value = "device") String device) {
+        sessionPools.remove(device);
+        subOnlineCount();
+        logger.info("{}断开webSocket连接!当前人数为:{}", device, onlineNum);
+    }
+
+    //收到客户端信息后,根据接收人的username把消息推下去或者群发
+    // to=-1群发消息
+    @OnMessage
+    public void onMessage(String message) throws IOException {
+        logger.info("server get {}", message);
+    }
+
+    //错误时调用
+    @OnError
+    public void onError(Session session, Throwable throwable) {
+        logger.info("server get {}", throwable.getMessage());
+    }
+
+    public static void addOnlineCount() {
+        onlineNum.incrementAndGet();
+    }
+
+    public static void subOnlineCount() {
+        onlineNum.decrementAndGet();
+    }
+
+    public static AtomicInteger getOnlineNumber() {
+        return onlineNum;
+    }
+
+    public static ConcurrentHashMap<String, Session> getSessionPools() {
+        return sessionPools;
+    }
+}

+ 17 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/common/BDConst.java

@@ -0,0 +1,17 @@
+package com.huashe.park.application.common;
+
+public interface BDConst {
+    public interface REDIS_KEY {
+        String BD_POINT_KEY = "bd:point:";
+        String FENCE_BREAK_IN_KEY = "fence:break:in:";
+        String FENCE = "fence";
+    }
+
+    public interface MQTT_TOPIC {
+        String POINT_LOCATION_TOPIC = "/uwb/point/#";
+        String EVT_LOCATION_TOPIC = "/uwb/evt";
+
+        String DEVICE_LOCATION_TOPIC = "/uwb/point/%s";
+
+    }
+}

+ 21 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/common/enums/EvtStatus.java

@@ -0,0 +1,21 @@
+package com.huashe.park.application.common.enums;
+
+public enum EvtStatus {
+    NEW("0", "新增"), DISAPPEAR("1", "消散");
+
+    private final String code;
+    private final String info;
+
+    EvtStatus(String code, String info) {
+        this.code = code;
+        this.info = info;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getInfo() {
+        return info;
+    }
+}

+ 21 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/common/enums/EvtType.java

@@ -0,0 +1,21 @@
+package com.huashe.park.application.common.enums;
+
+public enum EvtType {
+    FENCE_IN("1", "围栏闯禁");
+
+    private final String code;
+    private final String info;
+
+    EvtType(String code, String info) {
+        this.code = code;
+        this.info = info;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getInfo() {
+        return info;
+    }
+}

+ 120 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/engine/EvtFusionEngine.java

@@ -0,0 +1,120 @@
+package com.huashe.park.application.engine;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.huashe.park.application.common.DateTimeUtil;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public abstract class EvtFusionEngine implements IFusionEngine {
+    private final static Logger logger = LoggerFactory.getLogger(EvtFusionEngine.class);
+
+    @Resource
+    private RedisCache redisCache;
+
+    private String engineName;
+
+    @Value("${evt-fusion.thread-pool-size:5}")
+    private int threadPoolSize;
+
+    @Resource(name = "threadPoolTaskExecutor")
+    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
+
+    public void init() {
+        List<LinkedBlockingQueue<JSONObject>> queue = getQueue();
+        for (int i = 0; i < threadPoolSize; i++) {
+            queue.add(new LinkedBlockingQueue<>());
+        }
+    }
+
+
+    public void setEngineName(String name) {
+        this.engineName = name;
+    }
+
+    public void push(JSONObject msg) {
+        String key = msg.getString("key");
+        if (StringUtils.isEmpty(key)) {
+            return;
+        }
+        int bucketIndex = computeHashModulo(key, threadPoolSize);
+        List<LinkedBlockingQueue<JSONObject>> queue = getQueue();
+        LinkedBlockingQueue<JSONObject> messageQueue = queue.get(bucketIndex);
+        messageQueue.offer(msg);
+    }
+
+    public void start() {
+        List<LinkedBlockingQueue<JSONObject>> queue = getQueue();
+        for (int i = 0; i < threadPoolSize; i++) {
+            int finalI = i;
+            threadPoolTaskExecutor.execute(() -> {
+                while (true) {
+                    try {
+                        JSONObject msg = queue.get(finalI).take();
+                        LocationInfo locationInfoNew = new LocationInfo(msg.getDouble("latitude"), msg.getDouble("longitude"), msg.getLong("srcTimestamp"));
+                        locationInfoNew.setMsg(msg);
+                        String key = getKey(locationInfoNew);
+                        if (!redisCache.hasKey(key)) {
+                            getBizId(locationInfoNew);
+                            redisCache.setCacheObject(key, locationInfoNew);
+                            newEvtCallback(locationInfoNew);
+                            continue;
+                        }
+                        LocationInfo locationInfo = redisCache.getCacheObject(key);
+                        locationInfoNew.setEvtTimestamp(DateTimeUtil.timestampMillis());
+                        // 判断消息是否需要融合
+                        if (check(locationInfo, locationInfoNew)) {
+                            locationInfo.setSrcTimestamp(locationInfoNew.getSrcTimestamp());
+                            locationInfo.setHandleTimestamp(DateTimeUtil.timestampMillis());
+                            redisCache.setCacheObject(key, locationInfo);
+                        } else {
+                            // 老数据释放
+                            processOlderData(locationInfo);
+                            getBizId(locationInfoNew);
+                            redisCache.setCacheObject(key, locationInfoNew);
+                            newEvtCallback(locationInfoNew);
+                        }
+                    } catch (InterruptedException e) {
+                        logger.error("{} error", this.engineName, e);
+                        // 重置中断状态
+                        Thread.currentThread().interrupt();
+                        // 根据业务逻辑决定是否继续执行
+                        if (Thread.currentThread().isInterrupted()) {
+                            logger.error("任务已中断,不再继续执行");
+                            break;
+                        }
+                    } catch (Exception e) {
+                        logger.error("{} error", this.engineName, e);
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * 计算字符串的哈希值并对某个数取余数。
+     *
+     * @param str    字符串
+     * @param modulo 取余数的基数
+     * @return 字符串哈希值对 modulo 取余的结果
+     */
+    private int computeHashModulo(String str, int modulo) {
+        long hash = 0;
+        long base = 31;
+        long baseMod = base % modulo;  // 预计算乘法因子
+
+        for (char c : str.toCharArray()) {
+            hash = (hash * baseMod + c) % modulo;  // 避免整数溢出
+        }
+
+        return (int) (hash % modulo);  // 最终结果转换为 int
+    }
+
+}

+ 30 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/engine/IFusionEngine.java

@@ -0,0 +1,30 @@
+package com.huashe.park.application.engine;
+
+import com.alibaba.fastjson2.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public interface IFusionEngine {
+    default Boolean check(LocationInfo older, LocationInfo newer) {
+        return false;
+    }
+
+    default String getKey(LocationInfo msg) {
+        return "not implement";
+    }
+
+    default void getBizId(LocationInfo msg) {
+    }
+
+    default void processOlderData(LocationInfo msg) {
+    }
+
+    default void newEvtCallback(LocationInfo msg) {
+    }
+
+    default List<LinkedBlockingQueue<JSONObject>> getQueue() {
+       return new ArrayList<>();
+    }
+}

+ 79 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/engine/LocationInfo.java

@@ -0,0 +1,79 @@
+package com.huashe.park.application.engine;
+
+import com.alibaba.fastjson2.JSONObject;
+
+public class LocationInfo {
+    double latitude;
+    double longitude;
+    long srcTimestamp; // 时间戳,单位毫秒
+
+    long handleTimestamp;
+
+    long evtTimestamp;
+
+    String bizId;
+
+    JSONObject msg;
+
+    public LocationInfo(double latitude, double longitude, long srcTimestamp) {
+        this.latitude = latitude;
+        this.longitude = longitude;
+        this.srcTimestamp = srcTimestamp;
+    }
+
+    public double getLatitude() {
+        return latitude;
+    }
+
+    public void setLatitude(double latitude) {
+        this.latitude = latitude;
+    }
+
+    public double getLongitude() {
+        return longitude;
+    }
+
+    public void setLongitude(double longitude) {
+        this.longitude = longitude;
+    }
+
+    public long getSrcTimestamp() {
+        return srcTimestamp;
+    }
+
+    public void setSrcTimestamp(long srcTimestamp) {
+        this.srcTimestamp = srcTimestamp;
+    }
+
+    public long getHandleTimestamp() {
+        return handleTimestamp;
+    }
+
+    public void setHandleTimestamp(long handleTimestamp) {
+        this.handleTimestamp = handleTimestamp;
+    }
+
+    public long getEvtTimestamp() {
+        return evtTimestamp;
+    }
+
+    public void setEvtTimestamp(long evtTimestamp) {
+        this.evtTimestamp = evtTimestamp;
+    }
+
+    public JSONObject getMsg() {
+        return msg;
+    }
+
+    public void setMsg(JSONObject msg) {
+        this.msg = msg;
+    }
+
+    public String getBizId() {
+        return bizId;
+    }
+
+    public void setBizId(String bizId) {
+        this.bizId = bizId;
+    }
+}

+ 149 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/engine/impl/FenceBreakInEngine.java

@@ -0,0 +1,149 @@
+package com.huashe.park.application.engine.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.huashe.park.application.common.DateTimeUtil;
+import com.huashe.park.application.common.geo.GeoUtils;
+import com.huashe.park.application.web.core.config.MqttCfg;
+import com.huashe.park.core.domain.BdFenceInfo;
+import com.huashe.park.core.domain.BdFenceVioEvt;
+import com.huashe.park.core.service.IBdFenceInfoService;
+import com.huashe.park.core.service.IBdFenceVioEvtService;
+import com.huashe.park.application.engine.EvtFusionEngine;
+import com.huashe.park.application.engine.LocationInfo;
+import com.huashe.park.application.bd.socket.FenceVioEvtSocketServer;
+import com.huashe.park.application.common.BDConst;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.huashe.park.application.common.enums.EvtStatus;
+import com.huashe.park.application.common.enums.EvtType;
+import net.dreamlu.iot.mqtt.spring.client.MqttClientTemplate;
+import org.apache.commons.lang3.ObjectUtils;
+import org.locationtech.jts.geom.Polygon;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+@Service
+@ConditionalOnBean(MqttCfg.class)
+public class FenceBreakInEngine extends EvtFusionEngine {
+    private static final Logger logger = LoggerFactory.getLogger(FenceBreakInEngine.class);
+
+    @Autowired
+    private IBdFenceInfoService fenceInfoService;
+
+    @Autowired
+    private IBdFenceVioEvtService vioEvtService;
+
+    @Resource
+    private RedisCache redisCache;
+
+    @Autowired
+    private MqttClientTemplate client;
+
+    /**
+     * The constant MAX_EVT_TIME_GAP.
+     * 单位:秒
+     *
+     * @author chen.cheng
+     */
+    private static final int MAX_EVT_TIME_GAP = 300;
+
+    @Autowired
+    private FenceVioEvtSocketServer fenceVioEvtSocketServer;
+
+    private final List<LinkedBlockingQueue<JSONObject>> messageQueueList = new ArrayList<>(5);
+
+    @PostConstruct
+    public void init() {
+        super.init();
+        this.setEngineName("围栏闯禁事件融合");
+        if (!redisCache.hasKey(BDConst.REDIS_KEY.FENCE)) {
+            List<BdFenceInfo> bdFenceInfos = fenceInfoService.selectBdFenceInfoList(new BdFenceInfo());
+            if (CollectionUtils.isEmpty(bdFenceInfos)) {
+                return;
+            }
+            bdFenceInfos.removeIf(item -> ObjectUtils.isEmpty(item.getPoly()) || ObjectUtils.isEmpty(GeoUtils.getPolygon(item.getPoly())));
+
+            redisCache.setCacheList(BDConst.REDIS_KEY.FENCE, bdFenceInfos);
+        }
+    }
+
+    @Override
+    public Boolean check(LocationInfo older, LocationInfo newer) {
+        long gap = newer.getSrcTimestamp() - older.getSrcTimestamp();
+        // 将gap 转换为秒
+        gap = gap / 1000;
+
+        String oldFenceId = older.getMsg().getString("fenceId");
+        String newerFenceId = newer.getMsg().getString("fenceId");
+        return gap <= MAX_EVT_TIME_GAP && oldFenceId.equals(newerFenceId);
+    }
+
+    @Override
+    public List<LinkedBlockingQueue<JSONObject>> getQueue() {
+        return messageQueueList;
+    }
+
+    @Override
+    public String getKey(LocationInfo msg) {
+        return BDConst.REDIS_KEY.FENCE_BREAK_IN_KEY + msg.getMsg().getString("deviceId");
+    }
+
+
+    @Override
+    public void getBizId(LocationInfo msg) {
+        BdFenceVioEvt bdFenceVioEvt = new BdFenceVioEvt();
+        bdFenceVioEvt.setFenceId(msg.getMsg().getLong("fenceId"));
+        bdFenceVioEvt.setLat(msg.getLatitude());
+        bdFenceVioEvt.setLng(msg.getLongitude());
+        bdFenceVioEvt.setEvtStatus(EvtStatus.NEW.getCode());
+        bdFenceVioEvt.setEvtType(EvtType.FENCE_IN.getCode());
+        bdFenceVioEvt.setEvtTime(DateTimeUtil.getDateFromMills(msg.getSrcTimestamp()));
+        bdFenceVioEvt.setEvtDesc(String.format("围栏闯禁: %s", msg.getMsg().getString("fenceName")));
+        vioEvtService.insertBdFenceVioEvt(bdFenceVioEvt);
+        msg.setBizId(bdFenceVioEvt.getId().toString());
+    }
+
+    @Override
+    public void processOlderData(LocationInfo msg) {
+        vioEvtService.updateBdFenceVioEvt(new BdFenceVioEvt() {
+            {
+                setFenceId(msg.getMsg().getLong("fenceId"));
+                setEvtStatus(EvtStatus.DISAPPEAR.getCode());
+            }
+        });
+    }
+
+    @Override
+    public void newEvtCallback(LocationInfo msg) {
+        fenceVioEvtSocketServer.broadcast(msg);
+    }
+
+    public void generateEvt(JSONObject msg, byte[] payload) {
+        List<BdFenceInfo> cacheList = redisCache.getCacheList(BDConst.REDIS_KEY.FENCE);
+        if (CollectionUtils.isEmpty(cacheList)) {
+            return;
+        }
+        Polygon polygon;
+        logger.info("fence info size: {}", msg);
+        for (BdFenceInfo fenceInfo : cacheList) {
+            polygon = GeoUtils.getPolygon(fenceInfo.getPoly());
+            if (GeoUtils.isPointInGeoFence(polygon, msg.getString("longitude"), msg.getString("latitude"))) {
+                logger.info("?>>>>>fence info size: {}", msg);
+                msg.put("fenceId", fenceInfo.getId());
+                msg.put("fenceName", fenceInfo.getDefenceName());
+                client.publish(BDConst.MQTT_TOPIC.EVT_LOCATION_TOPIC, JSON.toJSONBytes(msg));
+                break;
+            }
+        }
+    }
+}

+ 100 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/engine/impl/PointFusionEngine.java

@@ -0,0 +1,100 @@
+package com.huashe.park.application.engine.impl;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.huashe.park.application.common.DateTimeUtil;
+import com.huashe.park.core.domain.BdDevcTrailUwb;
+import com.huashe.park.core.service.IBdDevcTrailUwbService;
+import com.huashe.park.application.bd.socket.PointWebSocketServer;
+import com.huashe.park.application.common.BDConst;
+import com.huashe.park.application.web.core.config.MqttCfg;
+import com.huashe.park.application.engine.EvtFusionEngine;
+import com.huashe.park.application.engine.LocationInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * The type Point fusion engine.
+ *
+ * @author chen.cheng
+ */
+@Service
+@ConditionalOnBean(MqttCfg.class)
+public class PointFusionEngine extends EvtFusionEngine {
+
+    @Autowired
+    private IBdDevcTrailUwbService bdDevcTrailUwbService;
+
+    /**
+     * The constant MAX_POINT_DISTANCE.
+     * 单位米
+     *
+     * @author chen.cheng
+     */
+    private static final int MAX_POINT_DISTANCE = 5;
+
+    /**
+     * The constant MAX_POINT_TIME_GAP.
+     * 单位秒
+     *
+     * @author chen.cheng
+     */
+    private static final int MAX_POINT_TIME_GAP = 2;
+
+    @Autowired
+    private PointWebSocketServer webSocketServer;
+
+    private final List<LinkedBlockingQueue<JSONObject>> messageQueueList = new ArrayList<>(5);
+
+    @PostConstruct
+    public void init() {
+        super.init();
+        this.setEngineName("坐标点位抽稀");
+    }
+
+    @Override
+    public Boolean check(LocationInfo older, LocationInfo newer) {
+        long gap = newer.getSrcTimestamp() - older.getSrcTimestamp();
+        // 将gap 转换为秒
+        gap = gap / 1000;
+        boolean isSamePoint = Double.compare(older.getLatitude(), newer.getLatitude()) == 0 && Double.compare(older.getLongitude(), newer.getLongitude()) == 0;
+        return gap <= MAX_POINT_TIME_GAP && isSamePoint;
+    }
+    @Override
+    public String getKey(LocationInfo msg) {
+        return BDConst.REDIS_KEY.BD_POINT_KEY + msg.getMsg().getString("deviceId");
+    }
+
+    @Override
+    public List<LinkedBlockingQueue<JSONObject>> getQueue() {
+        return messageQueueList;
+    }
+
+    @Override
+    public void getBizId(LocationInfo msg) {
+        long evtTimestamp = msg.getEvtTimestamp();
+        BdDevcTrailUwb bdDevcTrailUwb = new BdDevcTrailUwb();
+        bdDevcTrailUwb.setDevcKey(msg.getMsg().getString("deviceId"));
+        bdDevcTrailUwb.setLat(msg.getLatitude());
+        bdDevcTrailUwb.setLng(msg.getLongitude());
+        bdDevcTrailUwb.setDt(DateTimeUtil.currentDateTime(DateTimeUtil.DateFormatter.yyyyMMdd));
+        bdDevcTrailUwb.setTp(MAX_POINT_TIME_GAP);
+        bdDevcTrailUwb.setStepIndex(DateTimeUtil.getStepIndexFromMills(MAX_POINT_TIME_GAP, evtTimestamp));
+        bdDevcTrailUwbService.insertBdDevcTrailUwb(bdDevcTrailUwb);
+        msg.setBizId(bdDevcTrailUwb.getId().toString());
+    }
+
+    @Override
+    public void newEvtCallback(LocationInfo msg) {
+        webSocketServer.sendInfo(msg.getMsg().getString("deviceId"), msg.getMsg().toJSONString());
+    }
+
+    public void pushDevcLocation(LocationInfo msg) {
+        webSocketServer.sendInfo(msg.getMsg().getString("deviceId"), msg.getMsg().toJSONString());
+    }
+}

+ 31 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/mqtt/UWBLocationListener.java

@@ -0,0 +1,31 @@
+package com.huashe.park.application.mqtt;
+
+import net.dreamlu.iot.mqtt.core.client.MqttClientCreator;
+import net.dreamlu.iot.mqtt.spring.client.event.MqttConnectedEvent;
+import net.dreamlu.iot.mqtt.spring.client.event.MqttDisconnectEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Service;
+
+@Service
+public class UWBLocationListener {
+    private static final Logger logger = LoggerFactory.getLogger(UWBLocationListener.class);
+
+    @Autowired
+    private MqttClientCreator mqttClientCreator;
+
+    @EventListener
+    public void onConnected(MqttConnectedEvent event) {
+        logger.info("MqttConnectedEvent:{}", event);
+    }
+
+    @EventListener
+    public void onDisconnect(MqttDisconnectEvent event) {
+        // 离线时更新重连时的密码,适用于类似阿里云 mqtt clientId 连接带时间戳的方式
+        logger.info("MqttDisconnectEvent:{}", event);
+        // 在断线时更新 clientId、username、password
+        mqttClientCreator.clientId("newClient" + System.currentTimeMillis()).username("newUserName").password("newPassword");
+    }
+}

+ 50 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/mqtt/UWBLocationSubscribeListener.java

@@ -0,0 +1,50 @@
+package com.huashe.park.application.mqtt;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.huashe.park.application.common.BDConst;
+import com.huashe.park.application.web.core.config.MqttCfg;
+import com.huashe.park.application.engine.impl.FenceBreakInEngine;
+import com.huashe.park.application.engine.impl.PointFusionEngine;
+import net.dreamlu.iot.mqtt.codec.MqttQoS;
+import net.dreamlu.iot.mqtt.spring.client.MqttClientSubscribe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.nio.charset.StandardCharsets;
+
+@Service
+@ConditionalOnBean(MqttCfg.class)
+public class UWBLocationSubscribeListener {
+    private static final Logger logger = LoggerFactory.getLogger(UWBLocationSubscribeListener.class);
+
+    @Autowired
+    private PointFusionEngine pointFusionEngine;
+
+    @Autowired
+    private FenceBreakInEngine fenceBreakInEngine;
+
+    @PostConstruct
+    public void init() {
+        pointFusionEngine.start();
+        fenceBreakInEngine.start();
+    }
+
+    @MqttClientSubscribe(value = BDConst.MQTT_TOPIC.POINT_LOCATION_TOPIC)
+    public void subQos0(String topic, byte[] payload) {
+        logger.debug("topic:{} payload:{}", topic, new String(payload, StandardCharsets.UTF_8));
+        JSONObject jsonObject = JSON.parseObject(payload);
+        pointFusionEngine.push(jsonObject);
+        fenceBreakInEngine.generateEvt(JSON.parseObject(payload), payload);
+    }
+
+    @MqttClientSubscribe(value = BDConst.MQTT_TOPIC.EVT_LOCATION_TOPIC, qos = MqttQoS.QOS0)
+    public void subQos1(String topic, byte[] payload) {
+        logger.debug("topic:{} payload:{}", topic, new String(payload, StandardCharsets.UTF_8));
+        fenceBreakInEngine.push(JSON.parseObject(payload));
+    }
+}

+ 112 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/web/controller/bd/BdDevcTrailUwbController.java

@@ -0,0 +1,112 @@
+package com.huashe.park.application.web.controller.bd;
+
+import com.alibaba.fastjson2.JSON;
+import com.huashe.park.application.common.BDConst;
+import com.huashe.park.application.common.DateTimeUtil;
+import com.huashe.park.core.domain.BdDevcTrailUwb;
+import com.huashe.park.core.service.IBdDevcTrailUwbService;
+import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import net.dreamlu.iot.mqtt.spring.client.MqttClientTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 室内坐标定位Controller
+ *
+ * @author ruoyi
+ * @date 2024-10-16
+ */
+@RestController
+@CrossOrigin
+@RequestMapping("/bd/devcTrailUwb")
+public class BdDevcTrailUwbController extends BaseController {
+    @Autowired
+    private IBdDevcTrailUwbService bdDevcTrailUwbService;
+
+    @Autowired
+    private MqttClientTemplate client;
+
+    /**
+     * 查询室内坐标定位列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(BdDevcTrailUwb bdDevcTrailUwb) {
+        startPage();
+        List<BdDevcTrailUwb> list = bdDevcTrailUwbService.selectBdDevcTrailUwbList(bdDevcTrailUwb);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出室内坐标定位列表
+     */
+    @Log(title = "室内坐标定位", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, BdDevcTrailUwb bdDevcTrailUwb) {
+        List<BdDevcTrailUwb> list = bdDevcTrailUwbService.selectBdDevcTrailUwbList(bdDevcTrailUwb);
+        ExcelUtil<BdDevcTrailUwb> util = new ExcelUtil<BdDevcTrailUwb>(BdDevcTrailUwb.class);
+        util.exportExcel(response, list, "室内坐标定位数据");
+    }
+
+    @PostMapping("/point")
+    @Anonymous
+    public void pushPoint(@RequestBody BdDevcTrailUwb bdDevcTrailUwb) {
+        Map<String, Object> map = new HashMap() {
+            {
+                put("latitude", bdDevcTrailUwb.getLat());
+                put("longitude", bdDevcTrailUwb.getLng());
+                put("srcTimestamp", DateTimeUtil.timestampMillis());
+                put("key", bdDevcTrailUwb.getDevcKey());
+                put("deviceId", bdDevcTrailUwb.getDevcKey());
+            }
+        };
+        client.publish(String.format(BDConst.MQTT_TOPIC.DEVICE_LOCATION_TOPIC, bdDevcTrailUwb.getDevcKey()), JSON.toJSONBytes(map));
+    }
+
+
+    /**
+     * 获取室内坐标定位详细信息
+     */
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return success(bdDevcTrailUwbService.selectBdDevcTrailUwbById(id));
+    }
+
+    /**
+     * 新增室内坐标定位
+     */
+    @Log(title = "室内坐标定位", businessType = BusinessType.INSERT)
+    @PostMapping
+    @Anonymous
+    public AjaxResult add(@RequestBody BdDevcTrailUwb bdDevcTrailUwb) {
+        return toAjax(bdDevcTrailUwbService.insertBdDevcTrailUwb(bdDevcTrailUwb));
+    }
+
+    /**
+     * 修改室内坐标定位
+     */
+    @Log(title = "室内坐标定位", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody BdDevcTrailUwb bdDevcTrailUwb) {
+        return toAjax(bdDevcTrailUwbService.updateBdDevcTrailUwb(bdDevcTrailUwb));
+    }
+
+    /**
+     * 删除室内坐标定位
+     */
+    @Log(title = "室内坐标定位", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(bdDevcTrailUwbService.deleteBdDevcTrailUwbByIds(ids));
+    }
+}

+ 96 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/web/controller/bd/BdFenceInfoController.java

@@ -0,0 +1,96 @@
+package com.huashe.park.application.web.controller.bd;
+
+
+import com.huashe.park.core.domain.BdFenceInfo;
+import com.huashe.park.core.service.IBdFenceInfoService;
+import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 围栏基础信息Controller
+ *
+ * @author ruoyi
+ * @date 2024-10-14
+ */
+@RestController
+@RequestMapping("/bd/fenceInfo")
+@CrossOrigin
+@Anonymous
+public class BdFenceInfoController extends BaseController {
+    @Autowired
+    private IBdFenceInfoService bdFenceInfoService;
+
+    /**
+     * 查询围栏基础信息列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(BdFenceInfo bdFenceInfo) {
+        startPage();
+        List<BdFenceInfo> list = bdFenceInfoService.selectBdFenceInfoList(bdFenceInfo);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出围栏基础信息列表
+     */
+    @Log(title = "围栏基础信息", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, BdFenceInfo bdFenceInfo) {
+        List<BdFenceInfo> list = bdFenceInfoService.selectBdFenceInfoList(bdFenceInfo);
+        ExcelUtil<BdFenceInfo> util = new ExcelUtil<BdFenceInfo>(BdFenceInfo.class);
+        util.exportExcel(response, list, "围栏基础信息数据");
+    }
+
+    /**
+     * 获取围栏基础信息详细信息
+     */
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return success(bdFenceInfoService.selectBdFenceInfoById(id));
+    }
+
+    /**
+     * 新增围栏基础信息
+     */
+    @Log(title = "围栏基础信息", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody BdFenceInfo bdFenceInfo) {
+        return toAjax(bdFenceInfoService.insertBdFenceInfo(bdFenceInfo));
+    }
+
+    /**
+     * 修改围栏基础信息
+     */
+    @Log(title = "围栏基础信息", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody BdFenceInfo bdFenceInfo) {
+        return toAjax(bdFenceInfoService.updateBdFenceInfo(bdFenceInfo));
+    }
+
+    /**
+     * 删除围栏基础信息
+     */
+    @Log(title = "围栏基础信息", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(bdFenceInfoService.deleteBdFenceInfoByIds(ids));
+    }
+}

+ 95 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/web/controller/bd/BdFenceVioEvtController.java

@@ -0,0 +1,95 @@
+package com.huashe.park.application.web.controller.bd;
+
+import com.huashe.park.core.domain.BdFenceVioEvt;
+import com.huashe.park.core.service.IBdFenceVioEvtService;
+import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 围栏闯禁事件Controller
+ *
+ * @author ruoyi
+ * @date 2024-10-14
+ */
+@RestController
+@RequestMapping("/bd/fenceVioEvt")
+@CrossOrigin
+@Anonymous
+public class BdFenceVioEvtController extends BaseController {
+    @Autowired
+    private IBdFenceVioEvtService bdFenceVioEvtService;
+
+    /**
+     * 查询围栏闯禁事件列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(BdFenceVioEvt bdFenceVioEvt) {
+        startPage();
+        List<BdFenceVioEvt> list = bdFenceVioEvtService.selectBdFenceVioEvtList(bdFenceVioEvt);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出围栏闯禁事件列表
+     */
+    @Log(title = "围栏闯禁事件", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, BdFenceVioEvt bdFenceVioEvt) {
+        List<BdFenceVioEvt> list = bdFenceVioEvtService.selectBdFenceVioEvtList(bdFenceVioEvt);
+        ExcelUtil<BdFenceVioEvt> util = new ExcelUtil<BdFenceVioEvt>(BdFenceVioEvt.class);
+        util.exportExcel(response, list, "围栏闯禁事件数据");
+    }
+
+    /**
+     * 获取围栏闯禁事件详细信息
+     */
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return success(bdFenceVioEvtService.selectBdFenceVioEvtById(id));
+    }
+
+    /**
+     * 新增围栏闯禁事件
+     */
+    @Log(title = "围栏闯禁事件", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody BdFenceVioEvt bdFenceVioEvt) {
+        return toAjax(bdFenceVioEvtService.insertBdFenceVioEvt(bdFenceVioEvt));
+    }
+
+    /**
+     * 修改围栏闯禁事件
+     */
+    @Log(title = "围栏闯禁事件", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody BdFenceVioEvt bdFenceVioEvt) {
+        return toAjax(bdFenceVioEvtService.updateBdFenceVioEvt(bdFenceVioEvt));
+    }
+
+    /**
+     * 删除围栏闯禁事件
+     */
+    @Log(title = "围栏闯禁事件", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(bdFenceVioEvtService.deleteBdFenceVioEvtByIds(ids));
+    }
+}

+ 20 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/web/core/config/MqttCfg.java

@@ -0,0 +1,20 @@
+package com.huashe.park.application.web.core.config;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties(prefix = "bd.mqtt")
+@ConditionalOnProperty(name = "bd.mqtt.enabled", havingValue = "true")
+public class MqttCfg {
+    private boolean enabled;
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+}

+ 125 - 0
bd-park/park-backend/park-application/src/main/java/com/huashe/park/application/web/core/config/SwaggerConfig.java

@@ -0,0 +1,125 @@
+package com.huashe.park.application.web.core.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.ruoyi.common.config.RuoYiConfig;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.models.auth.In;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.ApiKey;
+import springfox.documentation.service.AuthorizationScope;
+import springfox.documentation.service.Contact;
+import springfox.documentation.service.SecurityReference;
+import springfox.documentation.service.SecurityScheme;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+
+/**
+ * Swagger2的接口配置
+ * 
+ * @author ruoyi
+ */
+@Configuration
+public class SwaggerConfig
+{
+    /** 系统基础配置 */
+    @Autowired
+    private RuoYiConfig ruoyiConfig;
+
+    /** 是否开启swagger */
+    @Value("${swagger.enabled}")
+    private boolean enabled;
+
+    /** 设置请求的统一前缀 */
+    @Value("${swagger.pathMapping}")
+    private String pathMapping;
+
+    /**
+     * 创建API
+     */
+    @Bean
+    public Docket createRestApi()
+    {
+        return new Docket(DocumentationType.OAS_30)
+                // 是否启用Swagger
+                .enable(enabled)
+                // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
+                .apiInfo(apiInfo())
+                // 设置哪些接口暴露给Swagger展示
+                .select()
+                // 扫描所有有注解的api,用这种方式更灵活
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                // 扫描指定包中的swagger注解
+                // .apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
+                // 扫描所有 .apis(RequestHandlerSelectors.any())
+                .paths(PathSelectors.any())
+                .build()
+                /* 设置安全模式,swagger可以设置访问token */
+                .securitySchemes(securitySchemes())
+                .securityContexts(securityContexts())
+                .pathMapping(pathMapping);
+    }
+
+    /**
+     * 安全模式,这里指定token通过Authorization头请求头传递
+     */
+    private List<SecurityScheme> securitySchemes()
+    {
+        List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
+        apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
+        return apiKeyList;
+    }
+
+    /**
+     * 安全上下文
+     */
+    private List<SecurityContext> securityContexts()
+    {
+        List<SecurityContext> securityContexts = new ArrayList<>();
+        securityContexts.add(
+                SecurityContext.builder()
+                        .securityReferences(defaultAuth())
+                        .operationSelector(o -> o.requestMappingPattern().matches("/.*"))
+                        .build());
+        return securityContexts;
+    }
+
+    /**
+     * 默认的安全上引用
+     */
+    private List<SecurityReference> defaultAuth()
+    {
+        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+        authorizationScopes[0] = authorizationScope;
+        List<SecurityReference> securityReferences = new ArrayList<>();
+        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
+        return securityReferences;
+    }
+
+    /**
+     * 添加摘要信息
+     */
+    private ApiInfo apiInfo()
+    {
+        // 用ApiInfoBuilder进行定制
+        return new ApiInfoBuilder()
+                // 设置标题
+                .title("标题:若依管理系统_接口文档")
+                // 描述
+                .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
+                // 作者信息
+                .contact(new Contact(ruoyiConfig.getName(), null, null))
+                // 版本
+                .version("版本号:" + ruoyiConfig.getVersion())
+                .build();
+    }
+}

+ 1 - 0
bd-park/park-backend/park-application/src/main/resources/META-INF/spring-devtools.properties

@@ -0,0 +1 @@
+restart.include.json=/com.alibaba.fastjson2.*.jar

+ 104 - 0
bd-park/park-backend/park-application/src/main/resources/application-druid.yml

@@ -0,0 +1,104 @@
+# 数据源配置
+spring:
+  # redis 配置
+  redis:
+    # 地址
+    host: 172.192.10.105
+    # 端口,默认为6379
+    port: 30013
+    # 数据库索引
+    database: 1
+    # 密码
+    password:
+    # 连接超时时间
+    timeout: 10s
+    lettuce:
+      pool:
+        # 连接池中的最小空闲连接
+        min-idle: 0
+        # 连接池中的最大空闲连接
+        max-idle: 8
+        # 连接池的最大数据库连接数
+        max-active: 8
+        # #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: 3s
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 主库数据源
+      master:
+        url: jdbc:mysql://172.192.10.105:30002/hs_cps?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: root
+        password: root
+      # 从库数据源
+      slave:
+        # 从数据源开关/默认关闭
+        enabled: false
+        url:
+        username:
+        password:
+      # 初始连接数
+      initialSize: 5
+      # 最小连接池数量
+      minIdle: 10
+      # 最大连接池数量
+      maxActive: 20
+      # 配置获取连接等待超时的时间
+      maxWait: 60000
+      # 配置连接超时时间
+      connectTimeout: 30000
+      # 配置网络超时时间
+      socketTimeout: 60000
+      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+      timeBetweenEvictionRunsMillis: 60000
+      # 配置一个连接在池中最小生存的时间,单位是毫秒
+      minEvictableIdleTimeMillis: 300000
+      # 配置一个连接在池中最大生存的时间,单位是毫秒
+      maxEvictableIdleTimeMillis: 900000
+      # 配置检测连接是否有效
+      validationQuery: SELECT 1 FROM DUAL
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      webStatFilter:
+        enabled: true
+      statViewServlet:
+        enabled: true
+        # 设置白名单,不填则允许所有访问
+        allow:
+        url-pattern: /druid/*
+        # 控制台管理用户名和密码
+        login-username: ruoyi
+        login-password: 123456
+      filter:
+        stat:
+          enabled: true
+          # 慢SQL记录
+          log-slow-sql: true
+          slow-sql-millis: 1000
+          merge-sql: true
+        wall:
+          config:
+            multi-statement-allow: true
+mqtt:
+  client:
+    enabled: true
+    ip: 200.200.19.121
+    port: 31005
+    name: uwb-location-client
+    client-id: uwb-000001
+    global-subscribe:
+    timeout: 5
+    reconnect: true
+    re-interval: 5000
+    version: mqtt_3_1_1
+    read-buffer-size: 8KB
+    max-bytes-in-message: 10MB
+    keep-alive-secs: 60
+    clean-session: true
+    ssl:
+      enabled: false
+bd:
+  mqtt:
+    enabled: true

+ 105 - 0
bd-park/park-backend/park-application/src/main/resources/application-hm.yml

@@ -0,0 +1,105 @@
+# 数据源配置
+spring:
+  # redis 配置
+  redis:
+    # 地址
+    host: 192.168.0.100
+    # 端口,默认为6379
+    port: 6379
+    # 数据库索引
+    database: 1
+    # 密码
+    password:
+    # 连接超时时间
+    timeout: 10s
+    lettuce:
+      pool:
+        # 连接池中的最小空闲连接
+        min-idle: 0
+        # 连接池中的最大空闲连接
+        max-idle: 8
+        # 连接池的最大数据库连接数
+        max-active: 8
+        # #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: 3s
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 主库数据源
+      master:
+        url: jdbc:mysql://192.168.0.100:13306/hs_cps?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: root
+        password: ct!QAZ
+      # 从库数据源
+      slave:
+        # 从数据源开关/默认关闭
+        enabled: false
+        url:
+        username:
+        password:
+      # 初始连接数
+      initialSize: 5
+      # 最小连接池数量
+      minIdle: 10
+      # 最大连接池数量
+      maxActive: 20
+      # 配置获取连接等待超时的时间
+      maxWait: 60000
+      # 配置连接超时时间
+      connectTimeout: 30000
+      # 配置网络超时时间
+      socketTimeout: 60000
+      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+      timeBetweenEvictionRunsMillis: 60000
+      # 配置一个连接在池中最小生存的时间,单位是毫秒
+      minEvictableIdleTimeMillis: 300000
+      # 配置一个连接在池中最大生存的时间,单位是毫秒
+      maxEvictableIdleTimeMillis: 900000
+      # 配置检测连接是否有效
+      validationQuery: SELECT 1 FROM DUAL
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      webStatFilter:
+        enabled: true
+      statViewServlet:
+        enabled: true
+        # 设置白名单,不填则允许所有访问
+        allow:
+        url-pattern: /druid/*
+        # 控制台管理用户名和密码
+        login-username: ruoyi
+        login-password: 123456
+      filter:
+        stat:
+          enabled: true
+          # 慢SQL记录
+          log-slow-sql: true
+          slow-sql-millis: 1000
+          merge-sql: true
+        wall:
+          config:
+            multi-statement-allow: true
+
+mqtt:
+  client:
+    enabled: true
+    ip: xt.wenhq.top
+    port: 8581
+    name: uwb-location-client
+    client-id: uwb-000001
+    global-subscribe:
+    timeout: 5
+    reconnect: true
+    re-interval: 5000
+    version: mqtt_3_1_1
+    read-buffer-size: 8KB
+    max-bytes-in-message: 10MB
+    keep-alive-secs: 60
+    clean-session: true
+    ssl:
+      enabled: false
+bd:
+  mqtt:
+    enabled: true

+ 108 - 0
bd-park/park-backend/park-application/src/main/resources/application-k8s.yml

@@ -0,0 +1,108 @@
+server:
+  servlet:
+    # 应用的访问路径
+    context-path: /prod-api
+# 数据源配置
+spring:
+  # redis 配置
+  redis:
+    # 地址
+    host: 200.200.19.121
+    # 端口,默认为6379
+    port: 31001
+    # 数据库索引
+    database: 3
+    # 密码
+    password:
+    # 连接超时时间
+    timeout: 10s
+    lettuce:
+      pool:
+        # 连接池中的最小空闲连接
+        min-idle: 0
+        # 连接池中的最大空闲连接
+        max-idle: 8
+        # 连接池的最大数据库连接数
+        max-active: 8
+        # #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: 3s
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 主库数据源
+      master:
+        url: jdbc:mysql://200.200.19.121:31000/hs_cps?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: root
+        password: root
+      # 从库数据源
+      slave:
+        # 从数据源开关/默认关闭
+        enabled: false
+        url:
+        username:
+        password:
+      # 初始连接数
+      initialSize: 5
+      # 最小连接池数量
+      minIdle: 10
+      # 最大连接池数量
+      maxActive: 20
+      # 配置获取连接等待超时的时间
+      maxWait: 60000
+      # 配置连接超时时间
+      connectTimeout: 30000
+      # 配置网络超时时间
+      socketTimeout: 60000
+      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+      timeBetweenEvictionRunsMillis: 60000
+      # 配置一个连接在池中最小生存的时间,单位是毫秒
+      minEvictableIdleTimeMillis: 300000
+      # 配置一个连接在池中最大生存的时间,单位是毫秒
+      maxEvictableIdleTimeMillis: 900000
+      # 配置检测连接是否有效
+      validationQuery: SELECT 1 FROM DUAL
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      webStatFilter:
+        enabled: true
+      statViewServlet:
+        enabled: true
+        # 设置白名单,不填则允许所有访问
+        allow:
+        url-pattern: /druid/*
+        # 控制台管理用户名和密码
+        login-username: ruoyi
+        login-password: 123456
+      filter:
+        stat:
+          enabled: true
+          # 慢SQL记录
+          log-slow-sql: true
+          slow-sql-millis: 1000
+          merge-sql: true
+        wall:
+          config:
+            multi-statement-allow: true
+mqtt:
+  client:
+    enabled: true
+    ip: xt.wenhq.top
+    port: 8581
+    name: uwb-location-client
+    client-id: uwb-000001
+    global-subscribe:
+    timeout: 5
+    reconnect: true
+    re-interval: 5000
+    version: mqtt_3_1_1
+    read-buffer-size: 8KB
+    max-bytes-in-message: 10MB
+    keep-alive-secs: 60
+    clean-session: true
+    ssl:
+      enabled: false
+bd:
+  mqtt:
+    enabled: true

+ 104 - 0
bd-park/park-backend/park-application/src/main/resources/application-prod.yml

@@ -0,0 +1,104 @@
+# 数据源配置
+spring:
+  # redis 配置
+  redis:
+    # 地址
+    host: 127.0.0.1
+    # 端口,默认为6379
+    port: 6379
+    # 数据库索引
+    database: 1
+    # 密码
+    password:
+    # 连接超时时间
+    timeout: 10s
+    lettuce:
+      pool:
+        # 连接池中的最小空闲连接
+        min-idle: 0
+        # 连接池中的最大空闲连接
+        max-idle: 8
+        # 连接池的最大数据库连接数
+        max-active: 8
+        # #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: 3s
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 主库数据源
+      master:
+        url: jdbc:mysql://127.0.0.1:3306/hs_cps?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: hscps
+        password: hscps2024
+      # 从库数据源
+      slave:
+        # 从数据源开关/默认关闭
+        enabled: false
+        url:
+        username:
+        password:
+      # 初始连接数
+      initialSize: 5
+      # 最小连接池数量
+      minIdle: 10
+      # 最大连接池数量
+      maxActive: 20
+      # 配置获取连接等待超时的时间
+      maxWait: 60000
+      # 配置连接超时时间
+      connectTimeout: 30000
+      # 配置网络超时时间
+      socketTimeout: 60000
+      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+      timeBetweenEvictionRunsMillis: 60000
+      # 配置一个连接在池中最小生存的时间,单位是毫秒
+      minEvictableIdleTimeMillis: 300000
+      # 配置一个连接在池中最大生存的时间,单位是毫秒
+      maxEvictableIdleTimeMillis: 900000
+      # 配置检测连接是否有效
+      validationQuery: SELECT 1 FROM DUAL
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      webStatFilter:
+        enabled: true
+      statViewServlet:
+        enabled: true
+        # 设置白名单,不填则允许所有访问
+        allow:
+        url-pattern: /druid/*
+        # 控制台管理用户名和密码
+        login-username: ruoyi
+        login-password: 123456
+      filter:
+        stat:
+          enabled: true
+          # 慢SQL记录
+          log-slow-sql: true
+          slow-sql-millis: 1000
+          merge-sql: true
+        wall:
+          config:
+            multi-statement-allow: true
+mqtt:
+  client:
+    enabled: true
+    ip: xt.wenhq.top
+    port: 8581
+    name: uwb-location-client
+    client-id: uwb-000001
+    global-subscribe:
+    timeout: 5
+    reconnect: true
+    re-interval: 5000
+    version: mqtt_3_1_1
+    read-buffer-size: 8KB
+    max-bytes-in-message: 10MB
+    keep-alive-secs: 60
+    clean-session: true
+    ssl:
+      enabled: false
+bd:
+  mqtt:
+    enabled: false

+ 125 - 0
bd-park/park-backend/park-application/src/main/resources/application.yml

@@ -0,0 +1,125 @@
+# 项目相关配置
+ruoyi:
+  # 名称
+  name: traffic-eff-be
+  # 版本
+  version: 3.8.8
+  # 版权年份
+  copyrightYear: 2024
+  # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
+  profile: /opt/project/ruoyi/ruoyi-backend/upload-file-path
+  # 获取ip地址开关
+  addressEnabled: false
+  # 验证码类型 math 数字计算 char 字符验证
+  captchaType: math
+
+# 开发环境配置
+server:
+  # 服务器的HTTP端口,默认为8080
+  port: 28080
+  servlet:
+    # 应用的访问路径
+    context-path: /bd-api
+  tomcat:
+    # tomcat的URI编码
+    uri-encoding: UTF-8
+    # 连接数满后的排队数,默认为100
+    accept-count: 1000
+    threads:
+      # tomcat最大线程数,默认为200
+      max: 800
+      # Tomcat启动初始化的线程数,默认值10
+      min-spare: 100
+
+# 日志配置
+logging:
+  level:
+    com.ruoyi: debug
+    org.springframework: warn
+
+# 用户配置
+user:
+  password:
+    # 密码最大错误次数
+    maxRetryCount: 5
+    # 密码锁定时间(默认10分钟)
+    lockTime: 10
+
+# Spring配置
+spring:
+  # 资源信息
+  messages:
+    # 国际化资源文件路径
+    basename: i18n/messages
+  profiles:
+    active: druid
+  # 文件上传
+  servlet:
+    multipart:
+      # 单个文件大小
+      max-file-size: 10MB
+      # 设置总上传的文件大小
+      max-request-size: 20MB
+  # 服务模块
+  devtools:
+    restart:
+      # 热部署开关
+      enabled: true
+forest:
+  max-connections: 1000        # 连接池最大连接数
+  connect-timeout: 3000        # 连接超时时间,单位为毫秒
+  read-timeout: 3000           # 数据读取超时时间,单位为毫秒
+  backend: okhttp3 # 配置后端HTTP API为 okhttp3
+  ## 日志总开关,打开/关闭Forest请求/响应日志(默认为 true)
+  log-enabled: true
+  ## 打开/关闭Forest请求日志(默认为 true)
+  log-request: true
+  ## 打开/关闭Forest响应状态日志(默认为 true)
+  log-response-status: true
+  ## 打开/关闭Forest响应内容日志(默认为 false)
+  log-response-content: true
+# token配置
+token:
+  # 令牌自定义标识
+  header: Authorization
+  # 令牌密钥
+  secret: abcdefghijklmnopqrstuvwxyz
+  # 令牌有效期(默认30分钟)
+  expireTime: 76000
+
+# MyBatis配置
+mybatis:
+  # 搜索指定包别名
+  typeAliasesPackage: com.ruoyi.**.domain
+  # 配置mapper的扫描,找到所有的mapper.xml映射文件
+  mapperLocations: classpath*:mapper/**/*Mapper.xml
+  # 加载全局的配置文件
+  configLocation: classpath:mybatis/mybatis-config.xml
+
+# PageHelper分页插件
+pagehelper:
+  helperDialect: mysql
+  supportMethodsArguments: true
+  params: count=countSql
+
+# Swagger配置
+swagger:
+  # 是否开启swagger
+  enabled: true
+  # 请求前缀
+  pathMapping: /dev-api
+
+# 防止XSS攻击
+xss:
+  # 过滤开关
+  enabled: true
+  # 排除链接(多个用逗号分隔)
+  excludes: /system/notice
+  # 匹配链接
+  urlPatterns: /system/*,/monitor/*,/tool/*
+
+evt-fusion:
+  # 默认为false
+  enabled: false
+  thread-pool-size: 5
+

+ 2 - 0
bd-park/park-backend/park-application/src/main/resources/banner.txt

@@ -0,0 +1,2 @@
+Application Version: ${ruoyi.version}
+Spring Boot Version: ${spring-boot.version}

+ 38 - 0
bd-park/park-backend/park-application/src/main/resources/i18n/messages.properties

@@ -0,0 +1,38 @@
+#错误消息
+not.null=* 必须填写
+user.jcaptcha.error=验证码错误
+user.jcaptcha.expire=验证码已失效
+user.not.exists=用户不存在/密码错误
+user.password.not.match=用户不存在/密码错误
+user.password.retry.limit.count=密码输入错误{0}次
+user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
+user.password.delete=对不起,您的账号已被删除
+user.blocked=用户已封禁,请联系管理员
+role.blocked=角色已封禁,请联系管理员
+login.blocked=很遗憾,访问IP已被列入系统黑名单
+user.logout.success=退出成功
+
+length.not.valid=长度必须在{min}到{max}个字符之间
+
+user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
+user.password.not.valid=* 5-50个字符
+ 
+user.email.not.valid=邮箱格式错误
+user.mobile.phone.number.not.valid=手机号格式错误
+user.login.success=登录成功
+user.register.success=注册成功
+user.notfound=请重新登录
+user.forcelogout=管理员强制退出,请重新登录
+user.unknown.error=未知错误,请重新登录
+
+##文件上传消息
+upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
+upload.filename.exceed.length=上传的文件名最长{0}个字符
+
+##权限
+no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
+no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
+no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
+no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
+no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
+no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]

+ 93 - 0
bd-park/park-backend/park-application/src/main/resources/logback.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+	<property name="log.path" value="/opt/project/ruoyi/ruoyi-backend/logs" />
+    <!-- 日志输出格式 -->
+	<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+
+	<!-- 控制台输出 -->
+	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+	</appender>
+
+	<!-- 系统日志输出 -->
+	<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/sys-info.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+			<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 日志最大的历史 60天 -->
+			<maxHistory>60</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+		<filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>INFO</level>
+            <!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+	</appender>
+
+	<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/sys-error.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 日志最大的历史 60天 -->
+			<maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>ERROR</level>
+			<!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+			<!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+	<!-- 用户访问日志输出  -->
+    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/sys-user.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 按天回滚 daily -->
+            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 60天 -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+	<!-- 系统模块日志级别控制  -->
+	<logger name="com.ruoyi" level="info" />
+	<!-- Spring日志级别控制  -->
+	<logger name="org.springframework" level="warn" />
+
+	<root level="info">
+		<appender-ref ref="console" />
+	</root>
+
+	<!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="file_info" />
+        <appender-ref ref="file_error" />
+    </root>
+
+	<!--系统用户操作日志-->
+    <logger name="sys-user" level="info">
+        <appender-ref ref="sys-user"/>
+    </logger>
+</configuration>

+ 20 - 0
bd-park/park-backend/park-application/src/main/resources/mybatis/mybatis-config.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE configuration
+PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-config.dtd">
+<configuration>
+    <!-- 全局参数 -->
+    <settings>
+        <!-- 使全局的映射器启用或禁用缓存 -->
+        <setting name="cacheEnabled"             value="true"   />
+        <!-- 允许JDBC 支持自动生成主键 -->
+        <setting name="useGeneratedKeys"         value="true"   />
+        <!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
+        <setting name="defaultExecutorType"      value="SIMPLE" />
+		<!-- 指定 MyBatis 所用日志的具体实现 -->
+        <setting name="logImpl"                  value="SLF4J"  />
+        <!-- 使用驼峰命名法转换字段 -->
+		 <setting name="mapUnderscoreToCamelCase" value="true"/>
+	</settings>
+
+</configuration>

+ 1 - 0
bd-park/park-backend/park-application/version

@@ -0,0 +1 @@
+2.0

+ 137 - 0
bd-park/park-backend/park-common/pom.xml

@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.huashe</groupId>
+        <artifactId>bd-park</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>park-common</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <description>
+        common通用工具
+    </description>
+
+    <dependencies>
+        <!-- Spring框架基本的核心工具 -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context-support</artifactId>
+        </dependency>
+
+        <!-- SpringWeb模块 -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+        </dependency>
+
+        <!-- spring security 安全认证 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <!-- pagehelper 分页插件 -->
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 自定义验证注解 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <!--常用工具类 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+
+        <!-- JSON工具类 -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
+        <!-- 阿里JSON解析器 -->
+        <dependency>
+            <groupId>com.alibaba.fastjson2</groupId>
+            <artifactId>fastjson2</artifactId>
+        </dependency>
+
+        <!-- io常用工具类 -->
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+        <!-- excel工具 -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+        </dependency>
+
+        <!-- yml解析器 -->
+        <dependency>
+            <groupId>org.yaml</groupId>
+            <artifactId>snakeyaml</artifactId>
+        </dependency>
+
+        <!-- Token生成与解析-->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+        </dependency>
+
+        <!-- Jaxb -->
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+        </dependency>
+
+        <!-- redis 缓存操作 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+        <!-- pool 对象池 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+
+        <!-- 解析客户端操作系统、浏览器等 -->
+        <dependency>
+            <groupId>eu.bitwalker</groupId>
+            <artifactId>UserAgentUtils</artifactId>
+        </dependency>
+
+        <!-- servlet包 -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.locationtech.jts</groupId>
+            <artifactId>jts-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-math3</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 665 - 0
bd-park/park-backend/park-common/src/main/java/com/huashe/park/application/common/DateTimeUtil.java

@@ -0,0 +1,665 @@
+package com.huashe.park.application.common;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.text.SimpleDateFormat;
+import java.time.DayOfWeek;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalAdjusters;
+import java.time.temporal.WeekFields;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * The type Date time util.
+ *
+ * @author chen.cheng
+ */
+public class DateTimeUtil {
+
+    /**
+     * Current date time string.
+     *
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String currentDateTime() {
+        return DateTimeUtil.currentDateTime(DateFormatter.yyyy_MM_dd_HHmmss);
+    }
+
+    /**
+     * Parse date date.
+     *
+     * @param dateString the date string
+     * @return the date
+     * @author chen.cheng
+     */
+    public static Date parseDate(String dateString) {
+        return DateTimeUtil.parseDate(dateString, DateFormatter.yyyy_MM_dd_HHmmss);
+    }
+
+    /**
+     * Parse date date.
+     *
+     * @param dateString  the date string
+     * @param formatRegex the format regex
+     * @return the date
+     * @author chen.cheng
+     */
+    public static Date parseDate(String dateString, String formatRegex) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatRegex);
+        LocalDateTime dateTime = LocalDateTime.parse(dateString, formatter);
+        Instant instant = dateTime.atZone(ZoneId.of("GMT+08:00")).toInstant();
+        return Date.from(instant);
+    }
+
+    /**
+     * Minus day date.
+     *
+     * @param dayNum the day num
+     * @return the date
+     * @author chen.cheng
+     */
+    public static Date minusDay(Long dayNum) {
+        LocalDateTime now = LocalDateTime.now();
+        Instant instant = now.atZone(ZoneId.of("GMT+08:00")).toInstant();
+        return Date.from(instant);
+    }
+
+    /**
+     * Parse date string.
+     *
+     * @param localDateTime the local date time
+     * @param formatRegex   the format regex
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String parseDate(LocalDateTime localDateTime, String formatRegex) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatRegex);
+        return localDateTime.format(formatter);
+    }
+
+    /**
+     * Parse date string.
+     *
+     * @param localDate   the local date
+     * @param formatRegex the format regex
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String parseDate(LocalDate localDate, String formatRegex) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatRegex);
+        return localDate.format(formatter);
+    }
+
+    /**
+     * Current date time string.
+     *
+     * @param format the format
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String currentDateTime(String format) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
+        LocalDateTime now = LocalDateTime.now();
+        return now.format(formatter);
+    }
+
+    public static Integer getStepIndexFromMills(Integer step, long mills) {
+        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(mills), ZoneId.systemDefault());
+        int hour = localDateTime.getHour();
+        int second = localDateTime.getSecond();
+        return hour * 60 * 60 / step + second / step;
+    }
+
+    public static String getDateFromMills(long mills, String formatRegex) {
+        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(mills), ZoneId.systemDefault());
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatRegex);
+        return localDateTime.format(formatter);
+    }
+
+    public static String getDateFromMills(long mills) {
+        return getDateFromMills(mills, DateFormatter.yyyy_MM_dd_HHmmss);
+    }
+
+
+    /**
+     * Parse local date local date time.
+     *
+     * @param dateString  the date string
+     * @param formatRegex the format regex
+     * @return the local date time
+     * @author chen.cheng
+     */
+    public static LocalDateTime parseLocalDateTime(String dateString, String formatRegex) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatRegex);
+        LocalDateTime dateTime = LocalDateTime.parse(dateString, formatter);
+        return dateTime;
+    }
+
+    public static long timestampMillis() {
+        LocalDateTime localDateTime = LocalDateTime.now();
+        // 将 LocalDateTime 转换为 Instant
+        Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
+        // 获取毫秒时间戳
+        return instant.toEpochMilli();
+    }
+
+    /**
+     * Parse local date local date.
+     *
+     * @param dateString  the date string
+     * @param formatRegex the format regex
+     * @return the local date
+     * @author chen.cheng
+     */
+    public static LocalDate parseLocalDate(String dateString, String formatRegex) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatRegex);
+        LocalDate dateTime = LocalDate.parse(dateString, formatter);
+        return dateTime;
+    }
+
+    /**
+     * Parse date string string.
+     *
+     * @param dateString  the date string
+     * @param formatRegex the format regex
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String parseDateString(String dateString, String formatRegex) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateFormatter.yyyy_MM_dd_HHmmss);
+        LocalDateTime dateTime = LocalDateTime.parse(dateString, formatter);
+        return parseDate(dateTime, formatRegex);
+    }
+
+    /**
+     * Parse date string string.
+     *
+     * @param dateString     the date string
+     * @param srcFormatRegex the src format regex
+     * @param formatRegex    the format regex
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String parseDateString(String dateString, String srcFormatRegex, String formatRegex) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(srcFormatRegex);
+        LocalDateTime dateTime = LocalDateTime.parse(dateString, formatter);
+        return parseDate(dateTime, formatRegex);
+    }
+
+    /**
+     * Parse short date string string(yyyyMMdd).
+     *
+     * @param dateString     the date string
+     * @param srcFormatRegex the src format regex
+     * @param formatRegex    the format regex
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String parseShortDateString(String dateString, String srcFormatRegex, String formatRegex) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(srcFormatRegex);
+        LocalDate date = LocalDate.parse(dateString, formatter);
+        return parseDate(date, formatRegex);
+    }
+
+    /**
+     * Days of range list.
+     *
+     * @param startDate the start date
+     * @param endDate   the end date DateTimeUtil.daysOfRange("2020-05-06",
+     *                  "2020-09-02",DateFormatter.yyyy_MM_dd,DateFormatter.yyyyMMdd)
+     * @return the list
+     * @author chen.cheng
+     */
+    public static List<String> daysOfRange(String startDate, String endDate) {
+        return daysOfRange(startDate, endDate, DateFormatter.yyyy_MM_dd, DateFormatter.yyyy_MM_dd);
+    }
+
+    /**
+     * Minus month string.
+     *
+     * @param monthNum   the month num
+     * @param formatRegx the format regx
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String minusMonth(Long monthNum, String formatRegx) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatRegx);
+        LocalDateTime now = LocalDateTime.now();
+        now = now.minusMonths(monthNum);
+        return now.format(formatter);
+    }
+
+    /**
+     * Minus month string
+     *
+     * @param monthNum   month num
+     * @param formatRegx format regx
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String minusMonth(Integer monthNum, String formatRegx) {
+        return minusMonth(monthNum.longValue(), formatRegx);
+    }
+
+    /**
+     * Yesterday string.
+     *
+     * @param formatRegx the format regx
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String yesterday(String formatRegx) {
+        return minusDay(1L, formatRegx);
+    }
+
+    /**
+     * Minus month string.
+     *
+     * @param monthNum   the month num
+     * @param formatRegx the format regx
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String minusMonth(String date, String formatRegx, Long monthNum) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatRegx);
+        LocalDateTime localDateTime = parseLocalDateTime(date, formatRegx);
+        localDateTime = localDateTime.minusMonths(monthNum);
+        return localDateTime.format(formatter);
+    }
+
+    /**
+     * Date minus month string
+     *
+     * @param date       date
+     * @param formatRegx format regx
+     * @param monthNum   month num
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String dateMinusMonth(String date, String formatRegx, Long monthNum) {
+        return dateMinusMonth(date, DateFormatter.yyyyMMdd, formatRegx, monthNum);
+    }
+
+    /**
+     * Date minus month string
+     *
+     * @param date          date
+     * @param srcFormatRegx src format regx
+     * @param formatRegx    format regx
+     * @param monthNum      month num
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String dateMinusMonth(String date, String srcFormatRegx, String formatRegx, Long monthNum) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatRegx);
+        LocalDate localDateTime = parseLocalDate(date, srcFormatRegx);
+        localDateTime = localDateTime.minusMonths(monthNum);
+        return localDateTime.format(formatter);
+    }
+
+    /**
+     * Minus day string.
+     *
+     * @param dayNum     the day num
+     * @param formatRegx the format regx
+     * @return the string
+     * @author chen.cheng
+     */
+    public static String minusDay(Long dayNum, String formatRegx) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatRegx);
+        LocalDateTime now = LocalDateTime.now();
+        now = now.minusDays(dayNum);
+        return now.format(formatter);
+    }
+
+    /**
+     * Days of range list.
+     *
+     * @param startDate    the start date
+     * @param endDate      the end date
+     * @param paramFormat  the param format
+     * @param resultFormat the result format
+     * @return the list
+     * @author chen.cheng
+     */
+    public static List<String> daysOfRange(String startDate, String endDate, String paramFormat, String resultFormat) {
+        DateTimeFormatter resultFormatter = DateTimeFormatter.ofPattern(resultFormat);
+        DateTimeFormatter paramFormatter = DateTimeFormatter.ofPattern(paramFormat);
+        LocalDate dateTimeOfStart = LocalDate.parse(startDate, paramFormatter);
+        LocalDate dateTimeOfEnd = LocalDate.parse(endDate, paramFormatter);
+        List<String> days = new ArrayList<>();
+        while (!dateTimeOfStart.isAfter(dateTimeOfEnd)) {
+            days.add(dateTimeOfStart.format(resultFormatter));
+            dateTimeOfStart = dateTimeOfStart.plusDays(1L);
+        }
+        return days;
+    }
+
+    public static List<String> monthOfRange(String startDate, String endDate, String paramFormat, String resultFormat) {
+        DateTimeFormatter resultFormatter = DateTimeFormatter.ofPattern(resultFormat);
+        DateTimeFormatter paramFormatter = DateTimeFormatter.ofPattern(paramFormat);
+        LocalDate dateTimeOfStart = LocalDate.parse(startDate, paramFormatter);
+        LocalDate dateTimeOfEnd = LocalDate.parse(endDate, paramFormatter);
+        List<String> month = new ArrayList<>();
+        while (!dateTimeOfStart.isAfter(dateTimeOfEnd)) {
+            month.add(dateTimeOfStart.format(resultFormatter));
+            dateTimeOfStart = dateTimeOfStart.plusMonths(1L);
+        }
+        DateTimeFormatter ddFormatter = DateTimeFormatter.ofPattern(DateFormatter.DD);
+        int startDd = Integer.parseInt(dateTimeOfStart.format(ddFormatter));
+        int endDd = Integer.parseInt(dateTimeOfEnd.format(ddFormatter));
+        if (startDd > endDd) {
+            month.add(dateTimeOfEnd.format(resultFormatter));
+        }
+        return month;
+    }
+
+    /**
+     * Days of range list.
+     *
+     * @param startDate   the start date
+     * @param endDate     the end date
+     * @param paramFormat the param format
+     * @return the list
+     * @author chen.cheng
+     */
+    public static List<String> daysOfRange(String startDate, String endDate, String paramFormat) {
+        DateTimeFormatter resultFormatter = DateTimeFormatter.ofPattern(paramFormat);
+        DateTimeFormatter paramFormatter = DateTimeFormatter.ofPattern(paramFormat);
+        LocalDate dateTimeOfStart = LocalDate.parse(startDate, paramFormatter);
+        LocalDate dateTimeOfEnd = LocalDate.parse(endDate, paramFormatter);
+        List<String> days = new ArrayList<>();
+        while (!dateTimeOfStart.isAfter(dateTimeOfEnd)) {
+            days.add(dateTimeOfStart.format(resultFormatter));
+            dateTimeOfStart = dateTimeOfStart.plusDays(1L);
+        }
+        return days;
+    }
+
+    /**
+     * Gets time step of time index.
+     *
+     * @param tp  the tp
+     * @param gap the gap (now + gap minutes)
+     * @return the time step of time index
+     * @author chen.cheng
+     */
+    public static Integer getTimeStepOfTimeIndex(Integer tp, Integer gap) {
+        return getTimeStepIndexOfNow(tp, LocalDateTime.now().plus(gap, ChronoUnit.MINUTES));
+    }
+
+    /**
+     * Get time step index of now integer.
+     *
+     * @param tp         the tp
+     * @param toDateTime the to date time
+     * @return the integer
+     * @author chen.cheng
+     */
+    public static int getTimeStepIndexOfNow(Integer tp, LocalDateTime toDateTime) {
+        LocalDateTime zero = LocalDateTime.of(toDateTime.getYear(), toDateTime.getMonth(), toDateTime.getDayOfMonth(), 0, 0, 0);
+        Duration duration = Duration.between(zero, toDateTime);
+        double minutes = duration.toMinutes();
+        return (int) Math.floor(minutes / tp);
+    }
+
+
+    /**
+     * Gets time from step index. tp is min the format hh:mm:00
+     *
+     * @param stepIndex the step index
+     * @param tp        the tp
+     * @return the time from step index
+     * @author chen.cheng
+     */
+    public static String getTimeFromStepIndex(Integer stepIndex, Integer tp) {
+        Integer stepIndex2Min = stepIndex * tp;
+        String hour = StringUtils.leftPad(String.valueOf(stepIndex2Min / 60), 2, "0");
+        String min = StringUtils.leftPad(String.valueOf(stepIndex2Min % 60), 2, "0");
+        return String.format("%s:%s:%s", hour, min, "00");
+    }
+
+    /**
+     * Gets time from step index with out second.
+     *
+     * @param stepIndex the step index
+     * @param tp        the tp
+     * @return the time from step index with out second
+     * @author chen.cheng
+     */
+    public static String getTimeFromStepIndexWithOutSecond(Integer stepIndex, Integer tp) {
+        Integer stepIndex2Min = stepIndex * tp;
+        String hour = StringUtils.leftPad(String.valueOf(stepIndex2Min / 60), 2, "0");
+        String min = StringUtils.leftPad(String.valueOf(stepIndex2Min % 60), 2, "0");
+        return String.format("%s:%s", hour, min);
+    }
+
+    /**
+     * Gets day of week.
+     *
+     * @param date           the date
+     * @param paramFormatter the param formatter
+     * @return the day of week
+     * @author chen.cheng
+     */
+    public static Integer getDayOfWeek(String date, String paramFormatter) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(paramFormatter);
+        LocalDate l_da1 = LocalDate.parse(date, formatter);
+        DayOfWeek dayOfWeek = l_da1.getDayOfWeek();
+        return dayOfWeek.getValue();
+    }
+
+    /**
+     * Gets ali day of week.
+     *
+     * @param date the date
+     * @return the ali day of week
+     * @author chen.cheng
+     */
+    public static Integer getAliDayOfWeek(String date) {
+        return getDayOfWeek(date, DateFormatter.yyyyMMdd) - 1;
+    }
+
+    /**
+     * Cal week of year integer.
+     *
+     * @return the integer
+     * @author chen.cheng
+     */
+    public static Integer calWeekOfYear() {
+        return calWeekOfYear(currentDateTime(DateFormatter.yyyy_MM_dd));
+    }
+
+    public static Integer calLastWeekOfYear() {
+        return calWeekOfYear(currentDateTime(DateFormatter.yyyy_MM_dd)) - 1;
+    }
+
+    /**
+     * Cal week of year integer.
+     *
+     * @param date the date yyyy-MM-dd
+     * @return the integer
+     * @author chen.cheng
+     */
+    public static Integer calWeekOfYear(String date) {
+        LocalDate localDate = LocalDate.parse(date);
+        // 第一个参数:一周的第一天,不能为空
+        // 第二个参数:第一周的最小天数,从1到7
+        WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY, 1);
+        return localDate.get(weekFields.weekOfYear());
+    }
+
+    /**
+     * Cal week of year integer.
+     *
+     * @param date           the date
+     * @param paramFormatter the param formatter
+     * @return the integer
+     * @author chen.cheng
+     */
+    public static Integer calWeekOfYear(String date, String paramFormatter) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(paramFormatter);
+        LocalDate localDate = LocalDate.parse(date, formatter);
+
+        return calWeekOfYear(localDate.toString());
+    }
+
+    /**
+     * Get week time section string [ ].
+     *
+     * @param weekIndex the week index
+     * @return the string [ ]
+     * @author chen.cheng
+     */
+    public static String[] getWeekTimeSection(int weekIndex) {
+        return getWeekTimeSection(weekIndex, DateFormatter.yyyyMMdd);
+    }
+
+    /**
+     * Get week time section string [ ]. 获取前几周内的日期范围
+     *
+     * @param weekIndex the week index
+     * @return the string [ ]
+     * @author chen.cheng
+     */
+    public static String[] getWeekTimeSection(int weekIndex, String dateFormat) {
+        // weekIndex为前几周的周数,如:获取当前时间前第二周的时间 weekIndex=2
+        // 获取本周第一天
+        Calendar cal = Calendar.getInstance();
+        cal.add(Calendar.WEEK_OF_MONTH, 0);
+        cal.set(Calendar.DAY_OF_WEEK, 2);
+        Date first = cal.getTime();
+        Date last = cal.getTime();
+        String firstString = new SimpleDateFormat("yyyy-MM-dd").format(first) + " 00:00:00";
+        String lastString = new SimpleDateFormat("yyyy-MM-dd").format(last) + " 23:59:59";
+        DateTimeFormatter formatPatten = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        LocalDateTime firstTime = LocalDateTime.parse(firstString, formatPatten);
+        LocalDateTime lastTime = LocalDateTime.parse(lastString, formatPatten);
+        DateTimeFormatter resultDateFormat = DateTimeFormatter.ofPattern(dateFormat);
+        // 开始时间
+        firstTime = firstTime.plusDays(-(weekIndex * 7L));
+        // 结束时间
+        lastTime = lastTime.plusDays(-1);
+        return new String[]{firstTime.format(resultDateFormat), lastTime.format(resultDateFormat)};
+    }
+
+    public static String getFirstDayOfRecentYear(String dateFormat) {
+        // 获取当前日期
+        LocalDate today = LocalDate.now();
+
+        // 计算近一年的年份
+        int recentYear = today.getYear() - 1;
+
+        LocalDate localDate = LocalDate.of(recentYear, today.getMonth(), 1);
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
+        return localDate.format(formatter);
+    }
+
+    public static String getFirstDayOfThisYear(String dateFormat) {
+        // 获取当前日期
+        LocalDate today = LocalDate.now();
+
+        // 计算近一年的年份
+        int recentYear = today.getYear();
+
+        // 使用 TemporalAdjusters 来找到近一年的第一天
+        LocalDate localDate = LocalDate.of(recentYear, 1, 1).with(TemporalAdjusters.firstDayOfYear());
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
+        return localDate.format(formatter);
+    }
+
+    public static String getFirstDayOfRecentYear() {
+        return getFirstDayOfRecentYear(DateFormatter.yyyy_MM_dd);
+    }
+
+    public static String getFirstDayOfRecentMonth(String dateFormat) {
+        // 获取当前日期
+        LocalDate today = LocalDate.now();
+        // 使用 TemporalAdjusters 来找到近一个月的第一天
+        LocalDate with = today.minusMonths(1);
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
+        return with.format(formatter);
+    }
+
+    public static String getFirstDayOfRecentMonth() {
+        return getFirstDayOfRecentMonth(DateFormatter.yyyy_MM_dd);
+    }
+
+    public static void main(String[] args) {
+        System.out.println(DateTimeUtil.getStepIndexFromMills(10, System.currentTimeMillis()));
+    }
+
+
+    /**
+     * The interface Date formatter.
+     *
+     * @author chen.cheng
+     */
+    public interface DateFormatter {
+        /**
+         * The constant yyyy_MM_dd_HHmmss.
+         *
+         * @author chen.cheng
+         */
+        String yyyy_MM_dd_HHmmss = "yyyy-MM-dd HH:mm:ss";
+
+        /**
+         * The constant yyyyMMddHHmmss.
+         *
+         * @author chen.cheng
+         */
+        String yyyyMMddHHmmss = "yyyyMMddHHmmss";
+
+        /**
+         * The constant yyyy_MM_dd.
+         *
+         * @author chen.cheng
+         */
+        String yyyy_MM_dd = "yyyy-MM-dd";
+
+        String DD = "dd";
+
+        /**
+         * The constant yyyyMMdd.
+         *
+         * @author chen.cheng
+         */
+        String yyyyMMdd = "yyyyMMdd";
+
+        String yyyy_MM = "yyyy-MM";
+
+        /**
+         * The constant yyyyMM.
+         *
+         * @author chen.cheng
+         */
+        String yyyyMM = "yyyyMM";
+
+        /**
+         * The constant yyyy.
+         *
+         * @author chen.cheng
+         */
+        String yyyy = "yyyy";
+
+        /**
+         * To string string.
+         *
+         * @return the string
+         * @author chen.cheng
+         */
+        @Override
+        String toString();
+    }
+
+}

+ 67 - 0
bd-park/park-backend/park-common/src/main/java/com/huashe/park/application/common/geo/CoordinateConverter.java

@@ -0,0 +1,67 @@
+package com.huashe.park.application.common.geo;
+
+import org.apache.commons.math3.linear.*;
+
+public class CoordinateConverter {
+    // WGS84椭球体参数
+    private static final double A = 6378137.0; // 长半轴(米)
+    private static final double F = 1 / 298.257223563; // 扁率
+    private static final double B = A * (1 - F); // 短半轴
+    private static final double E = Math.sqrt(1 - (B * B) / (A * A)); // 第一偏心率
+
+    // 将经纬度转换为平面坐标(墨卡托投影)
+    public static double[] latLonToXY(double latitude, double longitude) {
+        double x = A * Math.toRadians(longitude);
+        double y = A * Math.log(Math.tan(Math.PI / 4 + Math.toRadians(latitude) / 2));
+        return new double[]{x, y};
+    }
+
+    // 将平面坐标转换为经纬度(墨卡托投影逆变换)
+    public static double[] xyToLatLon(double x, double y) {
+        double lon = Math.toDegrees(x / A);
+        double lat = Math.toDegrees(2 * Math.atan(Math.exp(y / A)) - Math.PI / 2);
+        return new double[]{lat, lon};
+    }
+
+    // 计算基准经度和比例因子
+    public static double[] calculateParameters(double[] pointA, double[] pointB) {
+        double lambda0 = (pointA[0] + pointB[0]) / (2 * A);
+        double scaleFactor = (pointA[1] - pointB[1]) / (A * Math.log(Math.tan(Math.PI / 4 + Math.toRadians(90) / 2) / Math.tan(Math.PI / 4 + Math.toRadians(-90) / 2)));
+        return new double[]{lambda0, scaleFactor};
+    }
+
+    public static void main(String[] args) {
+        // 定义已知的平面坐标和对应的经纬度
+        double[][] points = {{8, 14.63, 118.86839482667, 32.0131180416999}, {6, 0, 118.869042069359, 32.0131156239015}, {0, 15.3, 118.868399686907, 32.0133391503578}};
+
+        // 提取x, y和对应的经纬度
+        double[] x = new double[points.length];
+        double[] y = new double[points.length];
+        double[] lon = new double[points.length];
+        double[] lat = new double[points.length];
+
+        for (int i = 0; i < points.length; i++) {
+            x[i] = points[i][0];
+            y[i] = points[i][1];
+            lon[i] = points[i][2];
+            lat[i] = points[i][3];
+        }
+
+        // 构建线性方程组Ax=B
+        RealMatrix A = new Array2DRowRealMatrix(new double[][]{x, y,new double[]{1,1,1}});
+        DecompositionSolver solverLon = new QRDecomposition(A).getSolver();
+        DecompositionSolver solverLat = new QRDecomposition(A).getSolver();
+
+        // 解线性方程组得到系数
+        RealVector coeffsLon = solverLon.solve(new ArrayRealVector(lon));
+        RealVector coeffsLat = solverLat.solve(new ArrayRealVector(lat));
+
+        // 计算第四点的经纬度
+        double xNew = 4;
+        double yNew = 4;
+        double lonNew = coeffsLon.getEntry(0) * xNew + coeffsLon.getEntry(1) * yNew + coeffsLon.getEntry(2);
+        double latNew = coeffsLat.getEntry(0) * xNew + coeffsLat.getEntry(1) * yNew + coeffsLat.getEntry(2);
+
+        System.out.println("第四点的经纬度为: " + lonNew + ", " + latNew);
+    }
+}

+ 193 - 0
bd-park/park-backend/park-common/src/main/java/com/huashe/park/application/common/geo/GeoUtils.java

@@ -0,0 +1,193 @@
+package com.huashe.park.application.common.geo;
+
+import org.locationtech.jts.geom.*;
+import org.locationtech.jts.io.ParseException;
+import org.locationtech.jts.io.WKTReader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class GeoUtils {
+    private static final Logger log = LoggerFactory.getLogger(GeoUtils.class);
+    /**
+     * geometryFactory
+     */
+    private static final GeometryFactory geometryFactory = new GeometryFactory();
+
+    /**
+     * Gets distance.
+     *
+     * @param lat1 the lat 1
+     * @param lon1 the lon 1
+     * @param lat2 the lat 2
+     * @param lon2 the lon 2
+     * @return the distance
+     * @author chen.cheng
+     */
+    public static double getDistance(double lat1, double lon1, double lat2, double lon2) {
+        Point p1 = geometryFactory.createPoint(new Coordinate(lon1, lat1));
+        Point p2 = geometryFactory.createPoint(new Coordinate(lon2, lat2));
+        return p1.distance(p2);
+    }
+
+    /**
+     * Gets poly center.
+     * POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))
+     *
+     * @param wktPolygon the wkt polygon
+     * @return the poly center
+     * @author chen.cheng
+     */
+    public static Point getPolyCenter(String wktPolygon) {
+        // 创建WKTReader对象
+        WKTReader reader = new WKTReader(geometryFactory);
+        // 从WKT字符串中读取几何对象
+        Geometry geometry = null;
+        try {
+            geometry = reader.read(wktPolygon);
+        } catch (ParseException e) {
+            log.info("Invalid WKT string: " + e.getMessage());
+        }
+        // 获取中心点
+        return geometry.getCentroid();
+    }
+
+    /**
+     * getPolygon
+     * POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))
+     *
+     * @param wktPolygon the wkt polygon
+     * @return the poly center
+     * @author chen.cheng
+     */
+    public static Polygon getPolygon(String wktPolygon) {
+        // 创建WKTReader对象
+        WKTReader reader = new WKTReader(geometryFactory);
+        // 从WKT字符串中读取几何对象
+        Polygon geometry = null;
+        try {
+            geometry = (Polygon) reader.read(wktPolygon);
+        } catch (ParseException e) {
+            log.info("Invalid WKT string: " + e.getMessage());
+        }
+        // 获取中心点
+        return geometry;
+    }
+
+    /**
+     * 判断指定的GPS点是否在电子围栏内
+     *
+     * @param fencePointsList 包含电子围栏的经纬度数据的列表,格式为 "经度,纬度"
+     * @param pointStr        指定的GPS点,格式为 "经度,纬度"
+     * @return 如果在电子围栏内则返回true,否则返回false
+     */
+    public static boolean isPointInGeoFence(List<String> fencePointsList, String pointStr) {
+        // 将电子围栏的经纬度数据转换为坐标数组
+        Coordinate[] fencePoints = parseCoordinates(fencePointsList);
+
+        // 将指定的GPS点转换为坐标
+        Coordinate targetPoint = parseCoordinate(pointStr);
+
+        // 创建电子围栏多边形
+        Polygon geoFencePolygon = createPolygon(fencePoints);
+
+        // 创建指定的GPS点
+        Point point = geometryFactory.createPoint(targetPoint);
+
+        // 检查指定的GPS点是否在电子围栏内
+        return geoFencePolygon.contains(point);
+    }
+
+    /**
+     * 判断指定的GPS点是否在电子围栏内
+     *
+     * @param geoFencePolygon geo fence polygon
+     * @param pointStr        指定的GPS点,格式为 "经度,纬度"
+     * @return 如果在电子围栏内则返回true ,否则返回false
+     * @since 2.0.0
+     */
+    public static boolean isPointInGeoFence(Polygon geoFencePolygon, String pointStr) {
+        // 将指定的GPS点转换为坐标
+        Coordinate testPoint = parseCoordinate(pointStr);
+
+        // 创建指定的GPS点
+        Point point = geometryFactory.createPoint(testPoint);
+
+        // 检查指定的GPS点是否在电子围栏内
+        return geoFencePolygon.contains(point);
+    }
+
+    public static boolean isPointInGeoFence(Polygon geoFencePolygon, String lng, String lat) {
+        // 将指定的GPS点转换为坐标
+        Coordinate testPoint = parseCoordinate(lng, lat);
+
+        // 创建指定的GPS点
+        Point point = geometryFactory.createPoint(testPoint);
+
+        // 检查指定的GPS点是否在电子围栏内
+        return geoFencePolygon.contains(point);
+    }
+
+    /**
+     * 判断指定的GPS点是否在电子围栏内
+     *
+     * @param fencePointsList 包含电子围栏的经纬度数据的列表,格式为 "经度,纬度"
+     * @return 如果在电子围栏内则返回true,否则返回false
+     */
+    public static Polygon getPointInGeoFence(List<String> fencePointsList) {
+        // 将电子围栏的经纬度数据转换为坐标数组
+        Coordinate[] fencePoints = parseCoordinates(fencePointsList);
+        // 创建电子围栏
+        return createPolygon(fencePoints);
+    }
+
+
+    /**
+     * 根据GPS点集合创建多边形
+     *
+     * @param coordinates GPS点集合
+     * @return 多边形对象
+     */
+    private static Polygon createPolygon(Coordinate[] coordinates) {
+        // Ensure the polygon is closed by adding the first coordinate at the end if necessary
+        if (!coordinates[0].equals(coordinates[coordinates.length - 1])) {
+            Coordinate[] closedCoordinates = new Coordinate[coordinates.length + 1];
+            System.arraycopy(coordinates, 0, closedCoordinates, 0, coordinates.length);
+            closedCoordinates[closedCoordinates.length - 1] = coordinates[0];
+            coordinates = closedCoordinates;
+        }
+        return geometryFactory.createPolygon(coordinates);
+    }
+
+    /**
+     * 将包含经纬度数据的列表转换为坐标数组
+     *
+     * @param pointsList 包含经纬度数据的列表
+     * @return 坐标数组
+     */
+    private static Coordinate[] parseCoordinates(List<String> pointsList) {
+        Coordinate[] coordinates = new Coordinate[pointsList.size()];
+        for (int i = 0; i < pointsList.size(); i++) {
+            coordinates[i] = parseCoordinate(pointsList.get(i));
+        }
+        return coordinates;
+    }
+
+    /**
+     * 将经纬度数据字符串转换为坐标
+     *
+     * @param pointStr 经纬度数据字符串,格式为 "经度,纬度"
+     * @return 坐标
+     */
+    private static Coordinate parseCoordinate(String pointStr) {
+        String[] parts = pointStr.split(",");
+        double lon = Double.parseDouble(parts[0]);
+        double lat = Double.parseDouble(parts[1]);
+        return new Coordinate(lon, lat);
+    }
+
+    private static Coordinate parseCoordinate(String lng, String lat) {
+        return new Coordinate(Double.parseDouble(lng), Double.parseDouble(lat));
+    }
+}

+ 84 - 0
bd-park/park-backend/park-core/pom.xml

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<parent>
+        <groupId>com.huashe</groupId>
+        <artifactId>bd-park</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.huashe.park.application.bd-park</groupId>
+    <artifactId>park-core</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <description>
+        park-core核心模块
+    </description>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>1.8</java.version>
+        <ruoyi.version>3.8.8</ruoyi.version>
+        <commons.io.version>2.13.0</commons.io.version>
+        <apache.commons.version>3.12.0</apache.commons.version>
+        <fastjson.version>2.0.43</fastjson.version>
+    </properties>
+
+    <dependencies>
+        <!-- Alibaba Fastjson -->
+        <dependency>
+            <groupId>com.alibaba.fastjson2</groupId>
+            <artifactId>fastjson2</artifactId>
+            <version>${fastjson.version}</version>
+        </dependency>
+
+        <!-- Apache Lang3 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>${apache.commons.version}</version>
+        </dependency>
+
+        <!-- Commons Io -->
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>${commons.io.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.huashe.application</groupId>
+            <artifactId>ruoyi-common</artifactId>
+            <version>${ruoyi.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.huashe.application</groupId>
+            <artifactId>ruoyi-quartz</artifactId>
+            <version>${ruoyi.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.huashe</groupId>
+            <artifactId>park-common</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.0</version>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 135 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/domain/BdDevcTrailUwb.java

@@ -0,0 +1,135 @@
+package com.huashe.park.core.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 室内坐标定位对象 bd_devc_trail_uwb
+ *
+ * @author ruoyi
+ * @date 2024-10-16
+ */
+public class BdDevcTrailUwb extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 设备唯一键 */
+    @Excel(name = "设备唯一键")
+    private String devcKey;
+
+    /** 纬度 */
+    @Excel(name = "纬度")
+    private Double lat;
+
+    /** 经度 */
+    @Excel(name = "经度")
+    private Double lng;
+
+    /** 日期 */
+    @Excel(name = "日期")
+    private String dt;
+
+    private Integer stepIndex;
+
+    private Integer tp;
+
+    /** 所在空间唯一键 */
+    @Excel(name = "所在空间唯一键")
+    private String roomIndex;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setDevcKey(String devcKey)
+    {
+        this.devcKey = devcKey;
+    }
+
+    public String getDevcKey()
+    {
+        return devcKey;
+    }
+    public void setLat(Double lat)
+    {
+        this.lat = lat;
+    }
+
+    public Double getLat()
+    {
+        return lat;
+    }
+    public void setLng(Double lng)
+    {
+        this.lng = lng;
+    }
+
+    public Double getLng()
+    {
+        return lng;
+    }
+    public void setDt(String dt)
+    {
+        this.dt = dt;
+    }
+
+    public String getDt()
+    {
+        return dt;
+    }
+    public void setStepIndex(Integer stepIndex)
+    {
+        this.stepIndex = stepIndex;
+    }
+
+    public Integer getStepIndex()
+    {
+        return stepIndex;
+    }
+    public void setTp(Integer tp)
+    {
+        this.tp = tp;
+    }
+
+    public Integer getTp()
+    {
+        return tp;
+    }
+    public void setRoomIndex(String roomIndex)
+    {
+        this.roomIndex = roomIndex;
+    }
+
+    public String getRoomIndex()
+    {
+        return roomIndex;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("devcKey", getDevcKey())
+            .append("lat", getLat())
+            .append("lng", getLng())
+            .append("dt", getDt())
+            .append("stepIndex", getStepIndex())
+            .append("tp", getTp())
+            .append("roomIndex", getRoomIndex())
+            .append("updateTime", getUpdateTime())
+            .append("createTime", getCreateTime())
+            .append("createBy", getCreateBy())
+            .append("updateBy", getUpdateBy())
+            .toString();
+    }
+}

+ 107 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/domain/BdFenceInfo.java

@@ -0,0 +1,107 @@
+package com.huashe.park.core.domain;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.locationtech.jts.geom.Polygon;
+
+/**
+ * 围栏基础信息对象 bd_fence_info
+ *
+ * @author ruoyi
+ * @date 2024-10-14
+ */
+public class BdFenceInfo extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    private Long id;
+
+    /** 围栏名称 */
+    @Excel(name = "围栏名称")
+    private String defenceName;
+
+    /** 围栏图形坐标 */
+    private String poly;
+
+    /** 中心点 */
+    @Excel(name = "中心点")
+    private Double centerLng;
+
+    /** 中心点 */
+    @Excel(name = "中心点")
+    private Double centerLat;
+
+    private Polygon polygon;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setDefenceName(String defenceName)
+    {
+        this.defenceName = defenceName;
+    }
+
+    public String getDefenceName()
+    {
+        return defenceName;
+    }
+    public void setPoly(String poly)
+    {
+        this.poly = poly;
+    }
+
+    public String getPoly()
+    {
+        return poly;
+    }
+    public void setCenterLng(Double centerLng)
+    {
+        this.centerLng = centerLng;
+    }
+
+    public Double getCenterLng()
+    {
+        return centerLng;
+    }
+    public void setCenterLat(Double centerLat)
+    {
+        this.centerLat = centerLat;
+    }
+
+    public Double getCenterLat()
+    {
+        return centerLat;
+    }
+
+    public Polygon getPolygon() {
+        return polygon;
+    }
+
+    public void setPolygon(Polygon polygon) {
+        this.polygon = polygon;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("defenceName", getDefenceName())
+            .append("poly", getPoly())
+            .append("centerLng", getCenterLng())
+            .append("centerLat", getCenterLat())
+            .append("updateTime", getUpdateTime())
+            .append("createTime", getCreateTime())
+            .append("createBy", getCreateBy())
+            .append("updateBy", getUpdateBy())
+            .toString();
+    }
+}

+ 146 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/domain/BdFenceVioEvt.java

@@ -0,0 +1,146 @@
+package com.huashe.park.core.domain;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 围栏闯禁事件对象 bd_fence_vio_evt
+ *
+ * @author ruoyi
+ * @date 2024-10-14
+ */
+public class BdFenceVioEvt extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    private Long id;
+
+    /**  */
+    @Excel(name = "")
+    private String evtKey;
+
+    /** 事件类型
+01 围栏闯禁事件 */
+    @Excel(name = "事件类型01 围栏闯禁事件")
+    private String evtType;
+
+    /** 事件描述 */
+    @Excel(name = "事件描述")
+    private String evtDesc;
+
+    /** 经度 */
+    @Excel(name = "经度")
+    private Double lng;
+
+    /** 维度 */
+    @Excel(name = "维度")
+    private Double lat;
+
+    /** 围栏id */
+    @Excel(name = "围栏id")
+    private Long fenceId;
+
+    private String evtStatus;
+
+    private String evtTime;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setEvtKey(String evtKey)
+    {
+        this.evtKey = evtKey;
+    }
+
+    public String getEvtKey()
+    {
+        return evtKey;
+    }
+    public void setEvtType(String evtType)
+    {
+        this.evtType = evtType;
+    }
+
+    public String getEvtType()
+    {
+        return evtType;
+    }
+    public void setEvtDesc(String evtDesc)
+    {
+        this.evtDesc = evtDesc;
+    }
+
+    public String getEvtDesc()
+    {
+        return evtDesc;
+    }
+    public void setLng(Double lng)
+    {
+        this.lng = lng;
+    }
+
+    public Double getLng()
+    {
+        return lng;
+    }
+    public void setLat(Double lat)
+    {
+        this.lat = lat;
+    }
+
+    public Double getLat()
+    {
+        return lat;
+    }
+    public void setFenceId(Long fenceId)
+    {
+        this.fenceId = fenceId;
+    }
+
+    public Long getFenceId()
+    {
+        return fenceId;
+    }
+
+    public String getEvtStatus() {
+        return evtStatus;
+    }
+
+    public void setEvtStatus(String evtStatus) {
+        this.evtStatus = evtStatus;
+    }
+
+    public String getEvtTime() {
+        return evtTime;
+    }
+
+    public void setEvtTime(String evtTime) {
+        this.evtTime = evtTime;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("evtKey", getEvtKey())
+            .append("evtType", getEvtType())
+            .append("evtDesc", getEvtDesc())
+            .append("lng", getLng())
+            .append("lat", getLat())
+            .append("fenceId", getFenceId())
+            .append("updateTime", getUpdateTime())
+            .append("createTime", getCreateTime())
+            .append("createBy", getCreateBy())
+            .append("updateBy", getUpdateBy())
+            .toString();
+    }
+}

+ 61 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/mapper/BdDevcTrailUwbMapper.java

@@ -0,0 +1,61 @@
+package com.huashe.park.core.mapper;
+
+import java.util.List;
+import com.huashe.park.core.domain.BdDevcTrailUwb;
+
+/**
+ * 室内坐标定位Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2024-10-16
+ */
+public interface BdDevcTrailUwbMapper 
+{
+    /**
+     * 查询室内坐标定位
+     * 
+     * @param id 室内坐标定位主键
+     * @return 室内坐标定位
+     */
+    public BdDevcTrailUwb selectBdDevcTrailUwbById(Long id);
+
+    /**
+     * 查询室内坐标定位列表
+     * 
+     * @param bdDevcTrailUwb 室内坐标定位
+     * @return 室内坐标定位集合
+     */
+    public List<BdDevcTrailUwb> selectBdDevcTrailUwbList(BdDevcTrailUwb bdDevcTrailUwb);
+
+    /**
+     * 新增室内坐标定位
+     * 
+     * @param bdDevcTrailUwb 室内坐标定位
+     * @return 结果
+     */
+    public int insertBdDevcTrailUwb(BdDevcTrailUwb bdDevcTrailUwb);
+
+    /**
+     * 修改室内坐标定位
+     * 
+     * @param bdDevcTrailUwb 室内坐标定位
+     * @return 结果
+     */
+    public int updateBdDevcTrailUwb(BdDevcTrailUwb bdDevcTrailUwb);
+
+    /**
+     * 删除室内坐标定位
+     * 
+     * @param id 室内坐标定位主键
+     * @return 结果
+     */
+    public int deleteBdDevcTrailUwbById(Long id);
+
+    /**
+     * 批量删除室内坐标定位
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteBdDevcTrailUwbByIds(Long[] ids);
+}

+ 62 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/mapper/BdFenceInfoMapper.java

@@ -0,0 +1,62 @@
+package com.huashe.park.core.mapper;
+
+import com.huashe.park.core.domain.BdFenceInfo;
+
+import java.util.List;
+
+/**
+ * 围栏基础信息Mapper接口
+ *
+ * @author ruoyi
+ * @date 2024-10-14
+ */
+public interface BdFenceInfoMapper
+{
+    /**
+     * 查询围栏基础信息
+     *
+     * @param id 围栏基础信息主键
+     * @return 围栏基础信息
+     */
+    public BdFenceInfo selectBdFenceInfoById(Long id);
+
+    /**
+     * 查询围栏基础信息列表
+     *
+     * @param bdFenceInfo 围栏基础信息
+     * @return 围栏基础信息集合
+     */
+    public List<BdFenceInfo> selectBdFenceInfoList(BdFenceInfo bdFenceInfo);
+
+    /**
+     * 新增围栏基础信息
+     *
+     * @param bdFenceInfo 围栏基础信息
+     * @return 结果
+     */
+    public int insertBdFenceInfo(BdFenceInfo bdFenceInfo);
+
+    /**
+     * 修改围栏基础信息
+     *
+     * @param bdFenceInfo 围栏基础信息
+     * @return 结果
+     */
+    public int updateBdFenceInfo(BdFenceInfo bdFenceInfo);
+
+    /**
+     * 删除围栏基础信息
+     *
+     * @param id 围栏基础信息主键
+     * @return 结果
+     */
+    public int deleteBdFenceInfoById(Long id);
+
+    /**
+     * 批量删除围栏基础信息
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteBdFenceInfoByIds(Long[] ids);
+}

+ 62 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/mapper/BdFenceVioEvtMapper.java

@@ -0,0 +1,62 @@
+package com.huashe.park.core.mapper;
+
+import com.huashe.park.core.domain.BdFenceVioEvt;
+
+import java.util.List;
+
+/**
+ * 围栏闯禁事件Mapper接口
+ *
+ * @author ruoyi
+ * @date 2024-10-14
+ */
+public interface BdFenceVioEvtMapper
+{
+    /**
+     * 查询围栏闯禁事件
+     *
+     * @param id 围栏闯禁事件主键
+     * @return 围栏闯禁事件
+     */
+    public BdFenceVioEvt selectBdFenceVioEvtById(Long id);
+
+    /**
+     * 查询围栏闯禁事件列表
+     *
+     * @param bdFenceVioEvt 围栏闯禁事件
+     * @return 围栏闯禁事件集合
+     */
+    public List<BdFenceVioEvt> selectBdFenceVioEvtList(BdFenceVioEvt bdFenceVioEvt);
+
+    /**
+     * 新增围栏闯禁事件
+     *
+     * @param bdFenceVioEvt 围栏闯禁事件
+     * @return 结果
+     */
+    public int insertBdFenceVioEvt(BdFenceVioEvt bdFenceVioEvt);
+
+    /**
+     * 修改围栏闯禁事件
+     *
+     * @param bdFenceVioEvt 围栏闯禁事件
+     * @return 结果
+     */
+    public int updateBdFenceVioEvt(BdFenceVioEvt bdFenceVioEvt);
+
+    /**
+     * 删除围栏闯禁事件
+     *
+     * @param id 围栏闯禁事件主键
+     * @return 结果
+     */
+    public int deleteBdFenceVioEvtById(Long id);
+
+    /**
+     * 批量删除围栏闯禁事件
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteBdFenceVioEvtByIds(Long[] ids);
+}

+ 62 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/IBdDevcTrailUwbService.java

@@ -0,0 +1,62 @@
+package com.huashe.park.core.service;
+
+import java.util.List;
+
+import com.huashe.park.core.domain.BdDevcTrailUwb;
+
+/**
+ * 室内坐标定位Service接口
+ * 
+ * @author ruoyi
+ * @date 2024-10-16
+ */
+public interface IBdDevcTrailUwbService 
+{
+    /**
+     * 查询室内坐标定位
+     * 
+     * @param id 室内坐标定位主键
+     * @return 室内坐标定位
+     */
+    public BdDevcTrailUwb selectBdDevcTrailUwbById(Long id);
+
+    /**
+     * 查询室内坐标定位列表
+     * 
+     * @param bdDevcTrailUwb 室内坐标定位
+     * @return 室内坐标定位集合
+     */
+    public List<BdDevcTrailUwb> selectBdDevcTrailUwbList(BdDevcTrailUwb bdDevcTrailUwb);
+
+    /**
+     * 新增室内坐标定位
+     * 
+     * @param bdDevcTrailUwb 室内坐标定位
+     * @return 结果
+     */
+    public int insertBdDevcTrailUwb(BdDevcTrailUwb bdDevcTrailUwb);
+
+    /**
+     * 修改室内坐标定位
+     * 
+     * @param bdDevcTrailUwb 室内坐标定位
+     * @return 结果
+     */
+    public int updateBdDevcTrailUwb(BdDevcTrailUwb bdDevcTrailUwb);
+
+    /**
+     * 批量删除室内坐标定位
+     * 
+     * @param ids 需要删除的室内坐标定位主键集合
+     * @return 结果
+     */
+    public int deleteBdDevcTrailUwbByIds(Long[] ids);
+
+    /**
+     * 删除室内坐标定位信息
+     * 
+     * @param id 室内坐标定位主键
+     * @return 结果
+     */
+    public int deleteBdDevcTrailUwbById(Long id);
+}

+ 62 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/IBdFenceInfoService.java

@@ -0,0 +1,62 @@
+package com.huashe.park.core.service;
+
+import com.huashe.park.core.domain.BdFenceInfo;
+
+import java.util.List;
+
+/**
+ * 围栏基础信息Service接口
+ *
+ * @author ruoyi
+ * @date 2024-10-14
+ */
+public interface IBdFenceInfoService
+{
+    /**
+     * 查询围栏基础信息
+     *
+     * @param id 围栏基础信息主键
+     * @return 围栏基础信息
+     */
+    public BdFenceInfo selectBdFenceInfoById(Long id);
+
+    /**
+     * 查询围栏基础信息列表
+     *
+     * @param bdFenceInfo 围栏基础信息
+     * @return 围栏基础信息集合
+     */
+    public List<BdFenceInfo> selectBdFenceInfoList(BdFenceInfo bdFenceInfo);
+
+    /**
+     * 新增围栏基础信息
+     *
+     * @param bdFenceInfo 围栏基础信息
+     * @return 结果
+     */
+    public int insertBdFenceInfo(BdFenceInfo bdFenceInfo);
+
+    /**
+     * 修改围栏基础信息
+     *
+     * @param bdFenceInfo 围栏基础信息
+     * @return 结果
+     */
+    public int updateBdFenceInfo(BdFenceInfo bdFenceInfo);
+
+    /**
+     * 批量删除围栏基础信息
+     *
+     * @param ids 需要删除的围栏基础信息主键集合
+     * @return 结果
+     */
+    public int deleteBdFenceInfoByIds(Long[] ids);
+
+    /**
+     * 删除围栏基础信息信息
+     *
+     * @param id 围栏基础信息主键
+     * @return 结果
+     */
+    public int deleteBdFenceInfoById(Long id);
+}

+ 62 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/IBdFenceVioEvtService.java

@@ -0,0 +1,62 @@
+package com.huashe.park.core.service;
+
+import com.huashe.park.core.domain.BdFenceVioEvt;
+
+import java.util.List;
+
+/**
+ * 围栏闯禁事件Service接口
+ *
+ * @author ruoyi
+ * @date 2024-10-14
+ */
+public interface IBdFenceVioEvtService
+{
+    /**
+     * 查询围栏闯禁事件
+     *
+     * @param id 围栏闯禁事件主键
+     * @return 围栏闯禁事件
+     */
+    public BdFenceVioEvt selectBdFenceVioEvtById(Long id);
+
+    /**
+     * 查询围栏闯禁事件列表
+     *
+     * @param bdFenceVioEvt 围栏闯禁事件
+     * @return 围栏闯禁事件集合
+     */
+    public List<BdFenceVioEvt> selectBdFenceVioEvtList(BdFenceVioEvt bdFenceVioEvt);
+
+    /**
+     * 新增围栏闯禁事件
+     *
+     * @param bdFenceVioEvt 围栏闯禁事件
+     * @return 结果
+     */
+    public int insertBdFenceVioEvt(BdFenceVioEvt bdFenceVioEvt);
+
+    /**
+     * 修改围栏闯禁事件
+     *
+     * @param bdFenceVioEvt 围栏闯禁事件
+     * @return 结果
+     */
+    public int updateBdFenceVioEvt(BdFenceVioEvt bdFenceVioEvt);
+
+    /**
+     * 批量删除围栏闯禁事件
+     *
+     * @param ids 需要删除的围栏闯禁事件主键集合
+     * @return 结果
+     */
+    public int deleteBdFenceVioEvtByIds(Long[] ids);
+
+    /**
+     * 删除围栏闯禁事件信息
+     *
+     * @param id 围栏闯禁事件主键
+     * @return 结果
+     */
+    public int deleteBdFenceVioEvtById(Long id);
+}

+ 97 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/impl/BdDevcTrailUwbServiceImpl.java

@@ -0,0 +1,97 @@
+package com.huashe.park.core.service.impl;
+
+import java.util.List;
+
+import com.huashe.park.core.domain.BdDevcTrailUwb;
+import com.huashe.park.core.mapper.BdDevcTrailUwbMapper;
+import com.huashe.park.core.service.IBdDevcTrailUwbService;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 室内坐标定位Service业务层处理
+ * 
+ * @author ruoyi
+ * @date 2024-10-16
+ */
+@Service
+public class BdDevcTrailUwbServiceImpl implements IBdDevcTrailUwbService
+{
+    @Autowired
+    private BdDevcTrailUwbMapper bdDevcTrailUwbMapper;
+
+    /**
+     * 查询室内坐标定位
+     * 
+     * @param id 室内坐标定位主键
+     * @return 室内坐标定位
+     */
+    @Override
+    public BdDevcTrailUwb selectBdDevcTrailUwbById(Long id)
+    {
+        return bdDevcTrailUwbMapper.selectBdDevcTrailUwbById(id);
+    }
+
+    /**
+     * 查询室内坐标定位列表
+     * 
+     * @param bdDevcTrailUwb 室内坐标定位
+     * @return 室内坐标定位
+     */
+    @Override
+    public List<BdDevcTrailUwb> selectBdDevcTrailUwbList(BdDevcTrailUwb bdDevcTrailUwb)
+    {
+        return bdDevcTrailUwbMapper.selectBdDevcTrailUwbList(bdDevcTrailUwb);
+    }
+
+    /**
+     * 新增室内坐标定位
+     * 
+     * @param bdDevcTrailUwb 室内坐标定位
+     * @return 结果
+     */
+    @Override
+    public int insertBdDevcTrailUwb(BdDevcTrailUwb bdDevcTrailUwb)
+    {
+        bdDevcTrailUwb.setCreateTime(DateUtils.getNowDate());
+        return bdDevcTrailUwbMapper.insertBdDevcTrailUwb(bdDevcTrailUwb);
+    }
+
+    /**
+     * 修改室内坐标定位
+     * 
+     * @param bdDevcTrailUwb 室内坐标定位
+     * @return 结果
+     */
+    @Override
+    public int updateBdDevcTrailUwb(BdDevcTrailUwb bdDevcTrailUwb)
+    {
+        bdDevcTrailUwb.setUpdateTime(DateUtils.getNowDate());
+        return bdDevcTrailUwbMapper.updateBdDevcTrailUwb(bdDevcTrailUwb);
+    }
+
+    /**
+     * 批量删除室内坐标定位
+     * 
+     * @param ids 需要删除的室内坐标定位主键
+     * @return 结果
+     */
+    @Override
+    public int deleteBdDevcTrailUwbByIds(Long[] ids)
+    {
+        return bdDevcTrailUwbMapper.deleteBdDevcTrailUwbByIds(ids);
+    }
+
+    /**
+     * 删除室内坐标定位信息
+     * 
+     * @param id 室内坐标定位主键
+     * @return 结果
+     */
+    @Override
+    public int deleteBdDevcTrailUwbById(Long id)
+    {
+        return bdDevcTrailUwbMapper.deleteBdDevcTrailUwbById(id);
+    }
+}

+ 98 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/impl/BdFenceInfoServiceImpl.java

@@ -0,0 +1,98 @@
+package com.huashe.park.core.service.impl;
+
+import com.huashe.park.application.common.geo.GeoUtils;
+import com.huashe.park.core.domain.BdFenceInfo;
+import com.huashe.park.core.mapper.BdFenceInfoMapper;
+import com.huashe.park.core.service.IBdFenceInfoService;
+import com.ruoyi.common.utils.DateUtils;
+import org.locationtech.jts.geom.Point;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 围栏基础信息Service业务层处理
+ *
+ * @author ruoyi
+ * @date 2024-10-14
+ */
+@Service
+public class BdFenceInfoServiceImpl implements IBdFenceInfoService {
+    @Autowired
+    private BdFenceInfoMapper bdFenceInfoMapper;
+
+    /**
+     * 查询围栏基础信息
+     *
+     * @param id 围栏基础信息主键
+     * @return 围栏基础信息
+     */
+    @Override
+    public BdFenceInfo selectBdFenceInfoById(Long id) {
+        return bdFenceInfoMapper.selectBdFenceInfoById(id);
+    }
+
+    /**
+     * 查询围栏基础信息列表
+     *
+     * @param bdFenceInfo 围栏基础信息
+     * @return 围栏基础信息
+     */
+    @Override
+    public List<BdFenceInfo> selectBdFenceInfoList(BdFenceInfo bdFenceInfo) {
+        return bdFenceInfoMapper.selectBdFenceInfoList(bdFenceInfo);
+    }
+
+    /**
+     * 新增围栏基础信息
+     *
+     * @param bdFenceInfo 围栏基础信息
+     * @return 结果
+     */
+    @Override
+    public int insertBdFenceInfo(BdFenceInfo bdFenceInfo) {
+        bdFenceInfo.setCreateTime(DateUtils.getNowDate());
+        Point polyCenter = GeoUtils.getPolyCenter(bdFenceInfo.getPoly());
+        bdFenceInfo.setCenterLat(polyCenter.getY());
+        bdFenceInfo.setCenterLng(polyCenter.getX());
+        return bdFenceInfoMapper.insertBdFenceInfo(bdFenceInfo);
+    }
+
+    /**
+     * 修改围栏基础信息
+     *
+     * @param bdFenceInfo 围栏基础信息
+     * @return 结果
+     */
+    @Override
+    public int updateBdFenceInfo(BdFenceInfo bdFenceInfo) {
+        bdFenceInfo.setUpdateTime(DateUtils.getNowDate());
+        Point polyCenter = GeoUtils.getPolyCenter(bdFenceInfo.getPoly());
+        bdFenceInfo.setCenterLat(polyCenter.getY());
+        bdFenceInfo.setCenterLng(polyCenter.getX());
+        return bdFenceInfoMapper.updateBdFenceInfo(bdFenceInfo);
+    }
+
+    /**
+     * 批量删除围栏基础信息
+     *
+     * @param ids 需要删除的围栏基础信息主键
+     * @return 结果
+     */
+    @Override
+    public int deleteBdFenceInfoByIds(Long[] ids) {
+        return bdFenceInfoMapper.deleteBdFenceInfoByIds(ids);
+    }
+
+    /**
+     * 删除围栏基础信息信息
+     *
+     * @param id 围栏基础信息主键
+     * @return 结果
+     */
+    @Override
+    public int deleteBdFenceInfoById(Long id) {
+        return bdFenceInfoMapper.deleteBdFenceInfoById(id);
+    }
+}

+ 97 - 0
bd-park/park-backend/park-core/src/main/java/com/huashe/park/core/service/impl/BdFenceVioEvtServiceImpl.java

@@ -0,0 +1,97 @@
+package com.huashe.park.core.service.impl;
+
+import com.huashe.park.core.domain.BdFenceVioEvt;
+import com.huashe.park.core.mapper.BdFenceVioEvtMapper;
+import com.huashe.park.core.service.IBdFenceVioEvtService;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 围栏闯禁事件Service业务层处理
+ *
+ * @author ruoyi
+ * @date 2024-10-14
+ */
+@Service
+public class BdFenceVioEvtServiceImpl implements IBdFenceVioEvtService
+{
+    @Autowired
+    private BdFenceVioEvtMapper bdFenceVioEvtMapper;
+
+    /**
+     * 查询围栏闯禁事件
+     *
+     * @param id 围栏闯禁事件主键
+     * @return 围栏闯禁事件
+     */
+    @Override
+    public BdFenceVioEvt selectBdFenceVioEvtById(Long id)
+    {
+        return bdFenceVioEvtMapper.selectBdFenceVioEvtById(id);
+    }
+
+    /**
+     * 查询围栏闯禁事件列表
+     *
+     * @param bdFenceVioEvt 围栏闯禁事件
+     * @return 围栏闯禁事件
+     */
+    @Override
+    public List<BdFenceVioEvt> selectBdFenceVioEvtList(BdFenceVioEvt bdFenceVioEvt)
+    {
+        return bdFenceVioEvtMapper.selectBdFenceVioEvtList(bdFenceVioEvt);
+    }
+
+    /**
+     * 新增围栏闯禁事件
+     *
+     * @param bdFenceVioEvt 围栏闯禁事件
+     * @return 结果
+     */
+    @Override
+    public int insertBdFenceVioEvt(BdFenceVioEvt bdFenceVioEvt)
+    {
+        bdFenceVioEvt.setCreateTime(DateUtils.getNowDate());
+        return bdFenceVioEvtMapper.insertBdFenceVioEvt(bdFenceVioEvt);
+    }
+
+    /**
+     * 修改围栏闯禁事件
+     *
+     * @param bdFenceVioEvt 围栏闯禁事件
+     * @return 结果
+     */
+    @Override
+    public int updateBdFenceVioEvt(BdFenceVioEvt bdFenceVioEvt)
+    {
+        bdFenceVioEvt.setUpdateTime(DateUtils.getNowDate());
+        return bdFenceVioEvtMapper.updateBdFenceVioEvt(bdFenceVioEvt);
+    }
+
+    /**
+     * 批量删除围栏闯禁事件
+     *
+     * @param ids 需要删除的围栏闯禁事件主键
+     * @return 结果
+     */
+    @Override
+    public int deleteBdFenceVioEvtByIds(Long[] ids)
+    {
+        return bdFenceVioEvtMapper.deleteBdFenceVioEvtByIds(ids);
+    }
+
+    /**
+     * 删除围栏闯禁事件信息
+     *
+     * @param id 围栏闯禁事件主键
+     * @return 结果
+     */
+    @Override
+    public int deleteBdFenceVioEvtById(Long id)
+    {
+        return bdFenceVioEvtMapper.deleteBdFenceVioEvtById(id);
+    }
+}

+ 97 - 0
bd-park/park-backend/park-core/src/main/resources/mapper/bd/BdDevcTrailUwbMapper.xml

@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.application.bd.mapper.BdDevcTrailUwbMapper">
+    
+    <resultMap type="BdDevcTrailUwb" id="BdDevcTrailUwbResult">
+        <result property="id"    column="id"    />
+        <result property="devcKey"    column="devc_key"    />
+        <result property="lat"    column="lat"    />
+        <result property="lng"    column="lng"    />
+        <result property="dt"    column="dt"    />
+        <result property="stepIndex"    column="step_index"    />
+        <result property="tp"    column="tp"    />
+        <result property="roomIndex"    column="room_index"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="updateBy"    column="update_by"    />
+    </resultMap>
+
+    <sql id="selectBdDevcTrailUwbVo">
+        select id, devc_key, lat, lng, dt, step_index, tp, room_index, update_time, create_time, create_by, update_by from bd_devc_trail_uwb
+    </sql>
+
+    <select id="selectBdDevcTrailUwbList" parameterType="BdDevcTrailUwb" resultMap="BdDevcTrailUwbResult">
+        <include refid="selectBdDevcTrailUwbVo"/>
+        <where>  
+            <if test="devcKey != null  and devcKey != ''"> and devc_key = #{devcKey}</if>
+            <if test="dt != null  and dt != ''"> and dt = #{dt}</if>
+        </where>
+    </select>
+    
+    <select id="selectBdDevcTrailUwbById" parameterType="Long" resultMap="BdDevcTrailUwbResult">
+        <include refid="selectBdDevcTrailUwbVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertBdDevcTrailUwb" parameterType="BdDevcTrailUwb" useGeneratedKeys="true" keyProperty="id">
+        insert into bd_devc_trail_uwb
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="devcKey != null">devc_key,</if>
+            <if test="lat != null">lat,</if>
+            <if test="lng != null">lng,</if>
+            <if test="dt != null">dt,</if>
+            <if test="stepIndex != null">step_index,</if>
+            <if test="tp != null">tp,</if>
+            <if test="roomIndex != null">room_index,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateBy != null">update_by,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="devcKey != null">#{devcKey},</if>
+            <if test="lat != null">#{lat},</if>
+            <if test="lng != null">#{lng},</if>
+            <if test="dt != null">#{dt},</if>
+            <if test="stepIndex != null">#{stepIndex},</if>
+            <if test="tp != null">#{tp},</if>
+            <if test="roomIndex != null">#{roomIndex},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+         </trim>
+    </insert>
+
+    <update id="updateBdDevcTrailUwb" parameterType="BdDevcTrailUwb">
+        update bd_devc_trail_uwb
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="devcKey != null">devc_key = #{devcKey},</if>
+            <if test="lat != null">lat = #{lat},</if>
+            <if test="lng != null">lng = #{lng},</if>
+            <if test="dt != null">dt = #{dt},</if>
+            <if test="stepIndex != null">step_index = #{stepIndex},</if>
+            <if test="tp != null">tp = #{tp},</if>
+            <if test="roomIndex != null">room_index = #{roomIndex},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteBdDevcTrailUwbById" parameterType="Long">
+        delete from bd_devc_trail_uwb where id = #{id}
+    </delete>
+
+    <delete id="deleteBdDevcTrailUwbByIds" parameterType="String">
+        delete from bd_devc_trail_uwb where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 84 - 0
bd-park/park-backend/park-core/src/main/resources/mapper/bd/BdFenceInfoMapper.xml

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.application.bd.mapper.BdFenceInfoMapper">
+
+    <resultMap type="BdFenceInfo" id="BdFenceInfoResult">
+        <result property="id"    column="id"    />
+        <result property="defenceName"    column="defence_name"    />
+        <result property="poly"    column="poly"    />
+        <result property="centerLng"    column="center_lng"    />
+        <result property="centerLat"    column="center_lat"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="updateBy"    column="update_by"    />
+    </resultMap>
+
+    <sql id="selectBdFenceInfoVo">
+        select id, defence_name, ST_AsText(poly) poly, center_lng, center_lat, update_time, create_time, create_by, update_by from bd_fence_info
+    </sql>
+
+    <select id="selectBdFenceInfoList" parameterType="BdFenceInfo" resultMap="BdFenceInfoResult">
+        <include refid="selectBdFenceInfoVo"/>
+        <where>
+            <if test="defenceName != null  and defenceName != ''"> and defence_name like concat('%', #{defenceName}, '%')</if>
+        </where>
+    </select>
+
+    <select id="selectBdFenceInfoById" parameterType="Long" resultMap="BdFenceInfoResult">
+        <include refid="selectBdFenceInfoVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertBdFenceInfo" parameterType="BdFenceInfo" useGeneratedKeys="true" keyProperty="id">
+        insert into bd_fence_info
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="defenceName != null">defence_name,</if>
+            <if test="poly != null">poly,</if>
+            <if test="centerLng != null">center_lng,</if>
+            <if test="centerLat != null">center_lat,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateBy != null">update_by,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="defenceName != null">#{defenceName},</if>
+            <if test="poly != null">ST_GeomFromText(#{poly}),</if>
+            <if test="centerLng != null">#{centerLng},</if>
+            <if test="centerLat != null">#{centerLat},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+         </trim>
+    </insert>
+
+    <update id="updateBdFenceInfo" parameterType="BdFenceInfo">
+        update bd_fence_info
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="defenceName != null">defence_name = #{defenceName},</if>
+            <if test="poly != null">poly = ST_GeomFromText(#{poly}),</if>
+            <if test="centerLng != null">center_lng = #{centerLng},</if>
+            <if test="centerLat != null">center_lat = #{centerLat},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteBdFenceInfoById" parameterType="Long">
+        delete from bd_fence_info where id = #{id}
+    </delete>
+
+    <delete id="deleteBdFenceInfoByIds" parameterType="String">
+        delete from bd_fence_info where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 118 - 0
bd-park/park-backend/park-core/src/main/resources/mapper/bd/BdFenceVioEvtMapper.xml

@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.application.bd.mapper.BdFenceVioEvtMapper">
+
+    <resultMap type="BdFenceVioEvt" id="BdFenceVioEvtResult">
+        <result property="id" column="id"/>
+        <result property="evtKey" column="evt_key"/>
+        <result property="evtType" column="evt_type"/>
+        <result property="evtDesc" column="evt_desc"/>
+        <result property="lng" column="lng"/>
+        <result property="lat" column="lat"/>
+        <result property="fenceId" column="fence_id"/>
+        <result property="evtStatus" column="evt_status"/>
+        <result property="evtTime" column="evt_time"/>
+        <result property="updateTime" column="update_time"/>
+        <result property="createTime" column="create_time"/>
+        <result property="createBy" column="create_by"/>
+        <result property="updateBy" column="update_by"/>
+    </resultMap>
+
+    <sql id="selectBdFenceVioEvtVo">
+        select id,
+               evt_key,
+               evt_type,
+               evt_desc,
+               lng,
+               lat,
+               fence_id,
+               evt_status,
+               evt_time,
+               update_time,
+               create_time,
+               create_by,
+               update_by
+        from bd_fence_vio_evt
+    </sql>
+
+    <select id="selectBdFenceVioEvtList" parameterType="BdFenceVioEvt" resultMap="BdFenceVioEvtResult">
+        <include refid="selectBdFenceVioEvtVo"/>
+        <where>
+            <if test="evtType != null  and evtType != ''">and evt_type = #{evtType}</if>
+            <if test="evtDesc != null  and evtDesc != ''">and evt_desc = #{evtDesc}</if>
+            <if test="evtStatus !=null and evtStatus!=''">and evt_status = #{evtStatus}</if>
+        </where>
+        order by id desc
+    </select>
+
+    <select id="selectBdFenceVioEvtById" parameterType="Long" resultMap="BdFenceVioEvtResult">
+        <include refid="selectBdFenceVioEvtVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertBdFenceVioEvt" parameterType="BdFenceVioEvt" useGeneratedKeys="true" keyProperty="id">
+        insert into bd_fence_vio_evt
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="evtKey != null">evt_key,</if>
+            <if test="evtType != null">evt_type,</if>
+            <if test="evtDesc != null">evt_desc,</if>
+            <if test="lng != null">lng,</if>
+            <if test="lat != null">lat,</if>
+            <if test="fenceId != null">fence_id,</if>
+            <if test="evtStatus !=null">evt_status,</if>
+            <if test="evtTime !=null">evt_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateBy != null">update_by,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="evtKey != null">#{evtKey},</if>
+            <if test="evtType != null">#{evtType},</if>
+            <if test="evtDesc != null">#{evtDesc},</if>
+            <if test="lng != null">#{lng},</if>
+            <if test="lat != null">#{lat},</if>
+            <if test="fenceId != null">#{fenceId},</if>
+            <if test="evtStatus !=null">#{evtStatus},</if>
+            <if test="evtTime !=null">#{evtTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+        </trim>
+    </insert>
+
+    <update id="updateBdFenceVioEvt" parameterType="BdFenceVioEvt">
+        update bd_fence_vio_evt
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="evtKey != null">evt_key = #{evtKey},</if>
+            <if test="evtType != null">evt_type = #{evtType},</if>
+            <if test="evtDesc != null">evt_desc = #{evtDesc},</if>
+            <if test="lng != null">lng = #{lng},</if>
+            <if test="lat != null">lat = #{lat},</if>
+            <if test="fenceId != null">fence_id = #{fenceId},</if>
+            <if test="evtStatus !=null">evt_status = #{evtStatus},</if>
+            <if test="evtTime !=null">evt_time = #{evtTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteBdFenceVioEvtById" parameterType="Long">
+        delete
+        from bd_fence_vio_evt
+        where id = #{id}
+    </delete>
+
+    <delete id="deleteBdFenceVioEvtByIds" parameterType="String">
+        delete from bd_fence_vio_evt where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 259 - 0
bd-park/park-backend/pom.xml

@@ -0,0 +1,259 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.huashe</groupId>
+    <artifactId>bd-park</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    
+    <modules>
+        <module>park-application</module>
+		<module>park-core</module>
+        <module>park-common</module>
+    </modules>
+
+    <description>
+        智慧园区管控
+    </description>
+    <properties>
+        <ruoyi.version>3.8.8</ruoyi.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>1.8</java.version>
+        <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
+        <spring-framework.version>5.3.33</spring-framework.version>
+        <spring-security.version>5.7.12</spring-security.version>
+        <druid.version>1.2.23</druid.version>
+        <bitwalker.version>1.21</bitwalker.version>
+        <swagger.version>3.0.0</swagger.version>
+        <kaptcha.version>2.3.3</kaptcha.version>
+        <pagehelper.boot.version>1.4.7</pagehelper.boot.version>
+        <fastjson.version>2.0.43</fastjson.version>
+        <oshi.version>6.6.1</oshi.version>
+        <commons.io.version>2.13.0</commons.io.version>
+        <poi.version>4.1.2</poi.version>
+        <velocity.version>2.3</velocity.version>
+        <jwt.version>0.9.1</jwt.version>
+        <forest.version>1.5.9</forest.version>
+        <cffu.version>1.0.0-Alpha19</cffu.version>
+        <jts.version>1.18.2</jts.version>
+        <mqttstarter.version>2.3.7</mqttstarter.version>
+        <math.version>3.6.1</math.version>
+    </properties>
+
+    <!-- 依赖声明 -->
+    <dependencyManagement>
+        <dependencies>
+
+            <!-- SpringFramework的依赖配置-->
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-framework-bom</artifactId>
+                <version>${spring-framework.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- SpringSecurity的依赖配置-->
+            <dependency>
+                <groupId>org.springframework.security</groupId>
+                <artifactId>spring-security-bom</artifactId>
+                <version>${spring-security.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- SpringBoot的依赖配置-->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>2.5.15</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- 阿里数据库连接池 -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid-spring-boot-starter</artifactId>
+                <version>${druid.version}</version>
+            </dependency>
+
+            <!-- 解析客户端操作系统、浏览器等 -->
+            <dependency>
+                <groupId>eu.bitwalker</groupId>
+                <artifactId>UserAgentUtils</artifactId>
+                <version>${bitwalker.version}</version>
+            </dependency>
+
+            <!-- pagehelper 分页插件 -->
+            <dependency>
+                <groupId>com.github.pagehelper</groupId>
+                <artifactId>pagehelper-spring-boot-starter</artifactId>
+                <version>${pagehelper.boot.version}</version>
+            </dependency>
+
+            <!-- 获取系统信息 -->
+            <dependency>
+                <groupId>com.github.oshi</groupId>
+                <artifactId>oshi-core</artifactId>
+                <version>${oshi.version}</version>
+            </dependency>
+
+            <!-- Swagger3依赖 -->
+            <dependency>
+                <groupId>io.springfox</groupId>
+                <artifactId>springfox-boot-starter</artifactId>
+                <version>${swagger.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>io.swagger</groupId>
+                        <artifactId>swagger-models</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+            <!-- io常用工具类 -->
+            <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>${commons.io.version}</version>
+            </dependency>
+
+            <!-- excel工具 -->
+            <dependency>
+                <groupId>org.apache.poi</groupId>
+                <artifactId>poi-ooxml</artifactId>
+                <version>${poi.version}</version>
+            </dependency>
+
+            <!-- velocity代码生成使用模板 -->
+            <dependency>
+                <groupId>org.apache.velocity</groupId>
+                <artifactId>velocity-engine-core</artifactId>
+                <version>${velocity.version}</version>
+            </dependency>
+
+            <!-- 阿里JSON解析器 -->
+            <dependency>
+                <groupId>com.alibaba.fastjson2</groupId>
+                <artifactId>fastjson2</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+
+            <!-- Token生成与解析-->
+            <dependency>
+                <groupId>io.jsonwebtoken</groupId>
+                <artifactId>jjwt</artifactId>
+                <version>${jwt.version}</version>
+            </dependency>
+
+            <!-- 验证码 -->
+            <dependency>
+                <groupId>pro.fessional</groupId>
+                <artifactId>kaptcha</artifactId>
+                <version>${kaptcha.version}</version>
+            </dependency>
+
+            <!-- 定时任务-->
+            <dependency>
+                <groupId>com.huashe.application</groupId>
+                <artifactId>ruoyi-quartz</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 代码生成-->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-generator</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 核心模块-->
+            <dependency>
+                <groupId>com.huashe.application</groupId>
+                <artifactId>ruoyi-framework</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 系统模块-->
+            <dependency>
+                <groupId>com.huashe.application</groupId>
+                <artifactId>ruoyi-system</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 通用工具-->
+            <dependency>
+                <groupId>com.huashe.application</groupId>
+                <artifactId>ruoyi-common</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.dtflys.forest</groupId>
+                <artifactId>forest-spring-boot-starter</artifactId>
+                <version>${forest.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.foldright</groupId>
+                <artifactId>cffu</artifactId>
+                <version>${cffu.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.locationtech.jts</groupId>
+                <artifactId>jts-core</artifactId>
+                <version>${jts.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>net.dreamlu</groupId>
+                <artifactId>mica-mqtt-client-spring-boot-starter</artifactId>
+                <version>${mqttstarter.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-math3</artifactId>
+                <version>${math.version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+    <repositories>
+        <repository>
+            <id>nexus</id>
+            <name>Team Nexus Repository</name>
+            <url>http://maven.xt.wenhq.top:8083/repository/maven-public/</url>
+            <snapshots>
+                <enabled>true</enabled>
+                <updatePolicy>always</updatePolicy>
+                <checksumPolicy>warn</checksumPolicy>
+            </snapshots>
+            <releases>
+                <enabled>true</enabled>
+                <updatePolicy>always</updatePolicy>
+                <checksumPolicy>warn</checksumPolicy>
+            </releases>
+        </repository>
+    </repositories>
+
+    <distributionManagement>
+        <repository>
+            <id>hs-private-repo</id>
+            <url>http://maven.xt.wenhq.top:8083/repository/maven-releases/</url>
+        </repository>
+        <snapshotRepository>
+            <id>hs-private-snapshot-repo</id>
+            <url>http://maven.xt.wenhq.top:8083/repository/maven-snapshots/</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>nexus</id>
+            <name>Team Nexus Repository</name>
+            <url>http://maven.xt.wenhq.top:8083/repository/maven-public/</url>
+        </pluginRepository>
+    </pluginRepositories>
+</project>