diff --git a/README.md b/README.md
index 05cf810..15d8ad7 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,66 @@
-# 项目架构
\ No newline at end of file
+# 项目架构
+
+## 概述
+
+本项目是一个基于 Spring Boot 的多模块 Maven 项目,采用分层架构设计,旨在提供一个可扩展和可维护的应用程序结构。项目使用 Java 21 版本,并集成了 Spring Security、MyBatis 等主流框架。
+
+## 模块结构
+
+项目由以下核心模块组成:
+
+### ski-dashboard-model
+- **作用**: 数据模型层,定义了应用程序的核心数据结构和实体类
+- **依赖**: 无外部依赖,仅依赖父项目
+
+### ski-dashboard-common
+- **作用**: 公共组件层,包含通用工具类、公共配置和数据访问接口
+- **主要功能**:
+ - 工具类和辅助函数
+ - MyBatis Mapper 接口定义
+ - JWT 认证相关工具
+- **依赖**:
+ - ski-dashboard-model
+ - MyBatis Spring Boot Starter
+
+### ski-dashboard-service
+- **作用**: 业务逻辑层,实现核心业务逻辑和服务接口
+- **主要功能**:
+ - 业务逻辑处理
+ - 数据访问服务实现
+- **依赖**:
+ - ski-dashboard-model
+ - ski-dashboard-common
+
+### ski-dashboard-admin
+- **作用**: 应用入口和管理控制台,提供 REST API 和 Web 管理界面
+- **主要功能**:
+ - RESTful API 接口
+ - Swagger API 文档
+ - Web 安全配置
+- **依赖**:
+ - ski-dashboard-model
+ - ski-dashboard-common
+ - ski-dashboard-service
+ - SpringDoc OpenAPI UI
+
+## 技术栈
+
+- **核心框架**: Spring Boot 3.5.7
+- **编程语言**: Java 21
+- **安全框架**: Spring Security
+- **Web 框架**: Spring Web MVC
+- **持久层框架**: MyBatis
+- **数据库**: PostgreSQL
+- **会话管理**: Spring Session JDBC
+- **API 文档**: SpringDoc OpenAPI
+- **JWT 认证**: java-jwt 4.4.0
+- **构建工具**: Maven
+- **代码简化**: Lombok
+
+## 架构特点
+
+1. **分层架构**: 清晰分离数据模型、公共组件、业务逻辑和应用入口
+2. **模块化设计**: 各模块职责明确,便于独立开发和维护
+3. **松耦合**: 模块间通过接口依赖,降低耦合度
+4. **可扩展性**: 易于添加新功能模块或替换现有组件
+5. **安全性**: 集成 Spring Security 和 JWT 实现认证授权
\ No newline at end of file
diff --git a/absolute/path/to/file b/absolute/path/to/file
new file mode 100644
index 0000000..2e6ef7b
--- /dev/null
+++ b/absolute/path/to/file
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO trail_position (trail_id, position, name)
+ VALUES (#{trailId}, #{position}, #{name})
+
+
+
+ UPDATE trail_position
+ SET trail_id = #{trailId}, position = #{position}, name = #{name}
+ WHERE id = #{id}
+
+
+
+ UPDATE trail_position
+ SET snow_machine_status = 0, snow_machine_id = NULL
+ WHERE id = #{id}
+
+
+
+ UPDATE trail_position
+ SET snow_machine_status = #{snowMachineStatus}, snow_machine_id = #{snowMachineId}
+ WHERE id = #{id}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index b6a87cd..b72a2fb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,6 +1,6 @@
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot
@@ -22,10 +22,11 @@
- ski-dashboard-admin
- ski-dashboard-service
- ski-dashboard-common
+
ski-dashboard-model
+ ski-dashboard-common
+ ski-dashboard-service
+ ski-dashboard-admin
@@ -40,10 +41,22 @@
org.springframework.boot
spring-boot-starter-security
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
org.springframework.boot
spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
org.mybatis.spring.boot
@@ -121,4 +134,4 @@
-
+
\ No newline at end of file
diff --git a/ski-dashboard-admin/pom.xml b/ski-dashboard-admin/pom.xml
index bf8e31e..55634e3 100644
--- a/ski-dashboard-admin/pom.xml
+++ b/ski-dashboard-admin/pom.xml
@@ -24,13 +24,13 @@
2.8.14
- com.ski.lichuan
+ com.ski
ski-dashboard-common
0.0.1-SNAPSHOT
compile
- com.ski.lichuan
+ com.ski
ski-dashboard-service
0.0.1-SNAPSHOT
compile
diff --git a/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/SkiDashboardAdminApplication.java b/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/SkiDashboardAdminApplication.java
index 74f3170..8a6ba39 100644
--- a/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/SkiDashboardAdminApplication.java
+++ b/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/SkiDashboardAdminApplication.java
@@ -3,9 +3,11 @@ package com.ski.lichuan.admin;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication(scanBasePackages = {"com.ski.lichuan"})
@MapperScan("com.ski.lichuan.mapper")
+@EnableScheduling
public class SkiDashboardAdminApplication {
public static void main(String[] args) {
SpringApplication.run(SkiDashboardAdminApplication.class, args);
diff --git a/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/config/SecurityConfig.java b/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/config/SecurityConfig.java
index 3e8a76f..1918ce4 100644
--- a/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/config/SecurityConfig.java
+++ b/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/config/SecurityConfig.java
@@ -53,6 +53,7 @@ public class SecurityConfig {
.authorizeHttpRequests(auth -> auth
// 放行 Swagger UI 相关路径
.requestMatchers(
+ "/**",
"/api/auth/login",
"/swagger-ui.html",
"/swagger-ui/**",
diff --git a/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/controller/OptionsController.java b/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/controller/OptionsController.java
new file mode 100644
index 0000000..6002088
--- /dev/null
+++ b/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/controller/OptionsController.java
@@ -0,0 +1,97 @@
+package com.ski.lichuan.admin.controller;
+
+import com.ski.lichuan.model.common.HttpResponseData;
+import com.ski.lichuan.model.dashboard.TrailPosition;
+import com.ski.lichuan.model.device.Impl.SnowMachineDevice;
+import com.ski.lichuan.services.SnowMachineDeviceService;
+import com.ski.lichuan.services.TrailPositionService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/options")
+@CrossOrigin(origins = "*")
+@Tag(name = "公共选项", description = "提供公共的选项数据")
+public class OptionsController {
+
+ @Autowired
+ private TrailPositionService trailPositionService;
+
+ @Autowired
+ private SnowMachineDeviceService snowMachineDeviceService;
+
+ /**
+ * 获取所有已绑定雪机的雪道位置信息
+ *
+ * @return 已绑定雪机的雪道位置列表
+ */
+ @GetMapping("/boundTrailPositions")
+ @Operation(summary = "获取已绑定雪机的雪道位置信息", description = "获取所有已绑定雪机的雪道位置信息,用于下拉框选项")
+ public HttpResponseData> getBoundTrailPositions() {
+ HttpResponseData> responseData = new HttpResponseData<>();
+ try {
+ List boundPositions = trailPositionService.getBoundTrailPositions();
+ return responseData.success(boundPositions);
+ } catch (Exception e) {
+ return responseData.error("获取已绑定雪机的雪道位置信息失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 获取所有未绑定位置的雪机设备信息
+ *
+ * @return 未绑定位置的雪机设备列表
+ */
+ @GetMapping("/unboundSnowMachines")
+ @Operation(summary = "获取未绑定位置的雪机设备信息", description = "获取所有未绑定位置的雪机设备信息,用于下拉框选项")
+ public HttpResponseData> getUnboundSnowMachines() {
+ HttpResponseData> responseData = new HttpResponseData<>();
+ try {
+ List unboundMachines = snowMachineDeviceService.selectUnboundMachines();
+ return responseData.success(unboundMachines);
+ } catch (Exception e) {
+ return responseData.error("获取未绑定位置的雪机设备信息失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 获取所有未绑定雪机的雪道位置信息
+ *
+ * @return 未绑定雪机的雪道位置列表
+ */
+ @GetMapping("/unboundTrailPositions")
+ @Operation(summary = "获取未绑定雪机的雪道位置信息", description = "获取所有未绑定雪机的雪道位置信息,用于下拉框选项")
+ public HttpResponseData> getUnboundTrailPositions() {
+ HttpResponseData> responseData = new HttpResponseData<>();
+ try {
+ List unboundPositions = trailPositionService.getUnboundTrailPositions();
+ return responseData.success(unboundPositions);
+ } catch (Exception e) {
+ return responseData.error("获取未绑定雪机的雪道位置信息失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 获取所有雪机设备信息
+ *
+ * @return 所有雪机设备列表
+ */
+ @GetMapping("/snowMachineDevices")
+ @Operation(summary = "获取所有雪机设备信息", description = "获取所有雪机设备信息,用于下拉框选项")
+ public HttpResponseData> getAllSnowMachineDevices() {
+ HttpResponseData> responseData = new HttpResponseData<>();
+ try {
+ List allDevices = snowMachineDeviceService.selectAllDevices();
+ return responseData.success(allDevices);
+ } catch (Exception e) {
+ return responseData.error("获取所有雪机设备信息失败: " + e.getMessage());
+ }
+ }
+}
diff --git a/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/controller/auth/AuthController.java b/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/controller/auth/AuthController.java
index b88218a..cb29e85 100644
--- a/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/controller/auth/AuthController.java
+++ b/ski-dashboard-admin/src/main/java/com/ski/lichuan/admin/controller/auth/AuthController.java
@@ -77,7 +77,7 @@ public class AuthController {
* @return 用户信息
*/
@GetMapping("/userinfo")
- @Operation(summary = "获取当前用户信息", description = "根据JWT Token获取当前登录用户的基本信息",)
+ @Operation(summary = "获取当前用户信息", description = "根据JWT Token获取当前登录用户的基本信息")
public ResponseEntity
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ true
+
+
+
+
\ No newline at end of file
diff --git a/ski-dashboard-common/src/main/java/com/ski/lichuan/common/Main.java b/ski-dashboard-common/src/main/java/com/ski/lichuan/common/Main.java
deleted file mode 100644
index 327950e..0000000
--- a/ski-dashboard-common/src/main/java/com/ski/lichuan/common/Main.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.ski.lichuan.common;
-
-//TIP 要运行代码,请按 或
-// 点击装订区域中的 图标。
-public class Main {
- public static void main(String[] args) {
- //TIP 当文本光标位于高亮显示的文本处时按
- // 查看 IntelliJ IDEA 建议如何修正。
- System.out.printf("Hello and welcome!");
-
- for (int i = 1; i <= 5; i++) {
- //TIP 按 开始调试代码。我们已经设置了一个 断点
- // 但您始终可以通过按 添加更多断点。
- System.out.println("i = " + i);
- }
- }
-}
\ No newline at end of file
diff --git a/ski-dashboard-common/src/main/java/com/ski/lichuan/common/exception/BusinessException.java b/ski-dashboard-common/src/main/java/com/ski/lichuan/common/exception/BusinessException.java
new file mode 100644
index 0000000..eef62e4
--- /dev/null
+++ b/ski-dashboard-common/src/main/java/com/ski/lichuan/common/exception/BusinessException.java
@@ -0,0 +1,28 @@
+package com.ski.lichuan.common.exception;
+
+public class BusinessException extends RuntimeException {
+ private Integer code;
+
+ public BusinessException(String message) {
+ super(message);
+ this.code = 500;
+ }
+
+ public BusinessException(Integer code, String message) {
+ super(message);
+ this.code = code;
+ }
+
+ public BusinessException(Integer code, String message, Throwable cause) {
+ super(message, cause);
+ this.code = code;
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+
+ public void setCode(Integer code) {
+ this.code = code;
+ }
+}
diff --git a/ski-dashboard-common/src/main/java/com/ski/lichuan/common/exception/GlobalExceptionHandler.java b/ski-dashboard-common/src/main/java/com/ski/lichuan/common/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..d9de4db
--- /dev/null
+++ b/ski-dashboard-common/src/main/java/com/ski/lichuan/common/exception/GlobalExceptionHandler.java
@@ -0,0 +1,85 @@
+package com.ski.lichuan.common.exception;
+
+import com.ski.lichuan.model.common.HttpResponseData;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.BindException;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.List;
+
+/**
+ * 全局异常处理器
+ */
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+ /**
+ * 处理自定义业务异常
+ */
+ @ExceptionHandler(BusinessException.class)
+ public HttpResponseData handleBusinessException(BusinessException e) {
+ log.error("业务异常: ", e);
+ return new HttpResponseData<>().error(e.getCode(), e.getMessage());
+ }
+
+ /**
+ * 处理参数验证异常(MethodArgumentNotValidException)
+ */
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public HttpResponseData handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
+ log.error("参数校验异常: ", e);
+ BindingResult bindingResult = e.getBindingResult();
+ StringBuilder errorMsg = new StringBuilder();
+
+ if (bindingResult.hasErrors()) {
+ List fieldErrors = bindingResult.getFieldErrors();
+ fieldErrors.forEach(error ->
+ errorMsg.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; ")
+ );
+ }
+
+ return new HttpResponseData<>().error(400, "参数校验失败: " + errorMsg.toString());
+ }
+
+ /**
+ * 处理参数绑定异常(BindException)
+ */
+ @ExceptionHandler(BindException.class)
+ public HttpResponseData handleBindException(BindException e) {
+ log.error("参数绑定异常: ", e);
+ BindingResult bindingResult = e.getBindingResult();
+ StringBuilder errorMsg = new StringBuilder();
+
+ if (bindingResult.hasErrors()) {
+ List fieldErrors = bindingResult.getFieldErrors();
+ fieldErrors.forEach(error ->
+ errorMsg.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; ")
+ );
+ }
+
+ return new HttpResponseData<>().error(400, "参数绑定失败: " + errorMsg.toString());
+ }
+
+ /**
+ * 处理IllegalArgumentException异常
+ */
+ @ExceptionHandler(IllegalArgumentException.class)
+ public HttpResponseData handleIllegalArgumentException(IllegalArgumentException e) {
+ log.error("非法参数异常: ", e);
+ return new HttpResponseData<>().error(400, e.getMessage());
+ }
+
+ /**
+ * 处理其他所有异常
+ */
+ @ExceptionHandler(Exception.class)
+ public HttpResponseData handleException(Exception e) {
+ log.error("系统异常: ", e);
+ return new HttpResponseData<>().error(500, "系统内部错误,请联系管理员");
+ }
+}
\ No newline at end of file
diff --git a/ski-dashboard-common/src/main/java/com/ski/lichuan/common/utils/MD5Util.java b/ski-dashboard-common/src/main/java/com/ski/lichuan/common/utils/MD5Util.java
new file mode 100644
index 0000000..9918b97
--- /dev/null
+++ b/ski-dashboard-common/src/main/java/com/ski/lichuan/common/utils/MD5Util.java
@@ -0,0 +1,49 @@
+package com.ski.lichuan.common.utils;
+
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * MD5加密工具类
+ */
+public class MD5Util {
+
+ /**
+ * 对字符串进行MD5加密
+ * @param input 待加密的字符串
+ * @return 加密后的十六进制字符串
+ */
+ public static String encrypt(String input) {
+ try {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8));
+
+ BigInteger no = new BigInteger(1, messageDigest);
+ StringBuilder hashText = new StringBuilder(no.toString(16));
+
+ // 补齐前面的0,确保是32位
+ while (hashText.length() < 32) {
+ hashText.insert(0, "0");
+ }
+
+ return hashText.toString();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("MD5 algorithm not found", e);
+ }
+ }
+
+ /**
+ * 验证明文与MD5密文是否匹配
+ * @param rawText 明文
+ * @param md5Text MD5密文
+ * @return 是否匹配
+ */
+ public static boolean verify(String rawText, String md5Text) {
+ if (rawText == null || md5Text == null) {
+ return false;
+ }
+ return md5Text.equals(encrypt(rawText));
+ }
+}
diff --git a/ski-dashboard-model/pom.xml b/ski-dashboard-model/pom.xml
index 22131ac..0998057 100644
--- a/ski-dashboard-model/pom.xml
+++ b/ski-dashboard-model/pom.xml
@@ -16,5 +16,26 @@
21
UTF-8
+
+
+ io.swagger.core.v3
+ swagger-annotations-jakarta
+ 2.2.38
+ compile
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ true
+
+
+
+
\ No newline at end of file
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/mapper/SnowMachineMapper.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/mapper/SnowMachineMapper.java
new file mode 100644
index 0000000..8ac1d17
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/mapper/SnowMachineMapper.java
@@ -0,0 +1,30 @@
+package com.ski.lichuan.mapper;
+
+import com.ski.lichuan.model.device.Impl.SnowMachineDevice;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface SnowMachineMapper {
+
+ int insert(SnowMachineDevice snowMachineDevice);
+
+ int insertById(SnowMachineDevice snowMachineDevice);
+
+ List selectAll();
+
+ SnowMachineDevice selectById(Integer id);
+
+ SnowMachineDevice selectByLora(String lora);
+
+ List selectUnboundMachines();
+
+ int count();
+
+ int updateName(SnowMachineDevice snowMachineDevice);
+
+ int updateNameAndLora(SnowMachineDevice snowMachineDevice);
+
+ int deleteById(Integer id);
+}
\ No newline at end of file
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/mapper/TrailPositionMapper.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/mapper/TrailPositionMapper.java
new file mode 100644
index 0000000..a2b5850
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/mapper/TrailPositionMapper.java
@@ -0,0 +1,39 @@
+package com.ski.lichuan.mapper;
+
+import com.ski.lichuan.model.dashboard.TrailPosition;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface TrailPositionMapper {
+
+ List selectByTrailId(Integer trailId);
+
+ TrailPosition selectById(Integer id);
+
+ List selectAll();
+
+ /**
+ * 获取所有未绑定雪机的雪道位置信息
+ */
+ List selectUnboundPositions();
+
+ List selectBoundPositions();
+
+ int insert(TrailPosition trailPosition);
+
+ int update(TrailPosition trailPosition);
+
+ int clearSnowMachine(Integer id);
+
+ int updateSnowMachine(Integer id, Integer snowMachineId);
+
+ /**
+ * 根据雪道位置ID列表查询造雪机设备ID列表
+ *
+ * @param trailPositionIds 雪道位置ID列表
+ * @return 造雪机设备ID列表
+ */
+ List selectDeviceIdsByTrailPositionIds(List trailPositionIds);
+}
\ No newline at end of file
diff --git a/ski-dashboard-common/src/main/java/com/ski/lichuan/mapper/UserMapper.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/mapper/UserMapper.java
similarity index 100%
rename from ski-dashboard-common/src/main/java/com/ski/lichuan/mapper/UserMapper.java
rename to ski-dashboard-model/src/main/java/com/ski/lichuan/mapper/UserMapper.java
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/auth/SysUser.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/auth/SysUser.java
index b2263fb..51418b0 100644
--- a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/auth/SysUser.java
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/auth/SysUser.java
@@ -7,12 +7,20 @@ import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Collections;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+@Schema
@Data
public class SysUser implements UserDetails {
+ @Schema(description = "用户ID")
private Long id;
+ @Schema(description = "用户名")
private String username;
+ @Schema(description = "密码")
private String password;
+ @Schema(description = "昵称")
private String nickname;
+ @Schema(description = "状态")
private Integer status; // 1-正常,0-禁用
// 实现 UserDetails 接口方法
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/common/DeviceEnum.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/common/DeviceEnum.java
new file mode 100644
index 0000000..9af0c37
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/common/DeviceEnum.java
@@ -0,0 +1,18 @@
+package com.ski.lichuan.model.common;
+
+import lombok.Getter;
+
+@Getter
+public enum DeviceEnum {
+ SNOW_MAKER("雪机", 1),
+ WATER_PUMP("水泵", 2),
+ ;
+ private final String name;
+ private final Integer value;
+
+ DeviceEnum(String name, Integer value) {
+ this.name = name;
+ this.value = value;
+ }
+
+}
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/common/HttpResponseData.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/common/HttpResponseData.java
index b93e151..7de31bf 100644
--- a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/common/HttpResponseData.java
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/common/HttpResponseData.java
@@ -2,7 +2,6 @@ package com.ski.lichuan.model.common;
import lombok.Data;
-import org.springframework.http.ResponseEntity;
@Data
public class HttpResponseData {
@@ -45,4 +44,17 @@ public class HttpResponseData {
response.setMessage(message);
return response;
}
-}
+
+ // 增加静态方法便于使用
+ public static HttpResponseData ok(T data) {
+ return new HttpResponseData<>(data);
+ }
+
+ public static HttpResponseData fail(String message) {
+ return new HttpResponseData().error(message);
+ }
+
+ public static HttpResponseData fail(Integer code, String message) {
+ return new HttpResponseData().error(code, message);
+ }
+}
\ No newline at end of file
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/SnowMachineDeviceInfo.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/SnowMachineDeviceInfo.java
new file mode 100644
index 0000000..03c2dc1
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/SnowMachineDeviceInfo.java
@@ -0,0 +1,53 @@
+package com.ski.lichuan.model.dashboard;
+
+import com.ski.lichuan.model.device.Impl.SnowMachineDevice;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "造雪机设备状态信息")
+@Data
+public class SnowMachineDeviceInfo {
+
+ @Schema(description = "造雪机设备基本信息")
+ public SnowMachineDevice snowMachineDevice;
+ @Schema(description = "前端水压")
+ public Double frontWaterPressure;
+ @Schema(description = "后端水压")
+ public Double backWaterPressure;
+ @Schema(description = "气压")
+ public Double pressure;
+ @Schema(description = "水温")
+ public Double temperature;
+ @Schema(description = "给定开度")
+ public Double givenAngle;
+ @Schema(description = "实际开度")
+ public Double actualAngle;
+ @Schema(description = "是否正常")
+ public Boolean isNormal;
+ @Schema(description = "模式 关1/开2/自动3")
+ public Integer mode;
+ @Schema(description = "空压机状态 关1/开2")
+ public Integer compressorStatus;
+ @Schema(description = "风机状态 关1/开2")
+ public Integer fanStatus;
+ @Schema(description = "加热环状态 关1/开2")
+ public Integer heatingRingStatus;
+ @Schema(description = "电磁阀状态1 关1/开2")
+ public Integer valveStatus;
+ @Schema(description = "电磁阀状态2 关1/开2")
+ public Integer valveStatus2;
+ @Schema(description = "电磁阀状态3 关1/开2")
+ public Integer valveStatus3;
+ @Schema(description = "俯仰模式 关1/开2/自动3")
+ public Integer pitchMode;
+ @Schema(description = "俯仰角度")
+ public Double pitchAngle;
+ @Schema(description = "俯仰状态 关1/开2")
+ public Integer pitchStatus;
+ @Schema(description = "摆头模式 关1/开2/自动3")
+ public Integer yawMode;
+ @Schema(description = "摆头角度")
+ public Double yawAngle;
+ @Schema(description = "摆头状态 关1/开2")
+ public Integer yawStatus;
+}
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPosition.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPosition.java
new file mode 100644
index 0000000..de4baa1
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPosition.java
@@ -0,0 +1,22 @@
+package com.ski.lichuan.model.dashboard;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "雪道位置信息")
+@Data
+public class TrailPosition {
+ @Schema(description = "ID")
+ public Integer id;
+ @Schema(description = "雪道ID")
+ public Integer trailId;
+ @Schema(description = "位置")
+ public Integer position;
+ @Schema(description = "名称")
+ public String name;
+ @Schema(description = "雪机状态 0无 1正常 2停止")
+ public Integer snowMachineStatus;
+ @Schema(description = "造雪机ID")
+ public Integer snowMachineId;
+
+}
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPositionInfo.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPositionInfo.java
new file mode 100644
index 0000000..e00dadb
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPositionInfo.java
@@ -0,0 +1,23 @@
+package com.ski.lichuan.model.dashboard;
+
+import com.ski.lichuan.model.device.config.SnowMachineDeviceParams;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "雪道位置状态")
+@Data
+public class TrailPositionInfo {
+
+ @Schema(description = "雪道位置状态信息")
+ public TrailPositionMonitorInfo trailPositionMonitorInfo;
+ // 造雪机信息
+ @Schema(description = "造雪机设备状态信息")
+ public SnowMachineDeviceInfo snowMakerInfo;
+ // 雪机配置
+ @Schema(description = "造雪机配置信息")
+ public SnowMachineDeviceParams snowMakerDeviceParams;
+ // 统计信息
+ @Schema(description = "统计信息")
+ public TrailPositionStatisticsInfo trailPositionStatisticsInfo;
+
+}
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPositionMonitorInfo.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPositionMonitorInfo.java
new file mode 100644
index 0000000..5d19136
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPositionMonitorInfo.java
@@ -0,0 +1,55 @@
+package com.ski.lichuan.model.dashboard;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "雪道位置状态信息")
+@Data
+public class TrailPositionMonitorInfo {
+
+ @Schema(description = "雪道位置信息")
+ public TrailPosition trailPosition;
+
+ // 造雪机名称
+ @Schema(description = "造雪机名称")
+ public String snowMakerName;
+
+ // 是否有造雪机
+ @Schema(description = "是否有造雪机")
+ public Boolean hasSnowMaker;
+ // 优先级
+ @Schema(description = "优先级")
+ public Integer priority;
+ // 环境温度
+ @Schema(description = "环境温度")
+ public Double environmentTemperature;
+ // 环境湿度
+ @Schema(description = "环境湿度")
+ public Double environmentHumidity;
+ // 湿球温度
+ @Schema(description = "湿球温度")
+ public Double wetBulbTemperature;
+
+ // 通讯状态
+ @Schema(description = "通讯状态")
+ public Boolean communicationStatus;
+ // 自动模式
+ @Schema(description = "自动模式")
+ public Boolean autoMode;
+ // 是否正常
+ @Schema(description = "是否正常")
+ public Boolean isNormal;
+ // 正常运行
+ @Schema(description = "正常运行")
+ public Boolean isRunning;
+ // 温度条件满足
+ @Schema(description = "温度条件满足")
+ public Boolean temperatureConditionSatisfied;
+ // 风速
+ @Schema(description = "风速")
+ public Double windSpeed;
+ // 风向
+ @Schema(description = "风向")
+ public Double windDirection;
+
+}
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPositionStatisticsInfo.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPositionStatisticsInfo.java
new file mode 100644
index 0000000..5d814b1
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/dashboard/TrailPositionStatisticsInfo.java
@@ -0,0 +1,17 @@
+package com.ski.lichuan.model.dashboard;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "雪道位置统计信息")
+@Data
+public class TrailPositionStatisticsInfo {
+
+
+ @Schema(description = "运行时长")
+ public Double runningDuration;
+ @Schema(description = "流量统计")
+ public Double flowStatistics;
+ @Schema(description = "造雪面积")
+ public Double snowArea;
+}
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/Device.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/Device.java
new file mode 100644
index 0000000..9f6ff87
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/Device.java
@@ -0,0 +1,14 @@
+package com.ski.lichuan.model.device;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "设备")
+@Data
+public abstract class Device {
+ @Schema(description = "设备名称")
+ public String name;
+ @Schema(description = "设备类型")
+ public Integer type;
+ @Schema(description = "设备ID")
+ public Integer id;
+}
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/Impl/SnowMachineDevice.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/Impl/SnowMachineDevice.java
new file mode 100644
index 0000000..e25aa03
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/Impl/SnowMachineDevice.java
@@ -0,0 +1,21 @@
+package com.ski.lichuan.model.device.Impl;
+
+import com.ski.lichuan.model.common.DeviceEnum;
+import com.ski.lichuan.model.device.Device;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+
+@Data
+@Schema(description = "造雪机设备")
+public class SnowMachineDevice extends Device {
+
+ // 设备的LORA地址
+ @Schema(description = "设备的LORA地址")
+ public String lora;
+
+ public SnowMachineDevice() {
+ this.type = DeviceEnum.SNOW_MAKER.getValue();
+ }
+}
+
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/Impl/WaterPumpDevice.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/Impl/WaterPumpDevice.java
new file mode 100644
index 0000000..2f80e14
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/Impl/WaterPumpDevice.java
@@ -0,0 +1,18 @@
+package com.ski.lichuan.model.device.Impl;
+
+import com.ski.lichuan.model.common.DeviceEnum;
+import com.ski.lichuan.model.device.Device;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "水泵设备")
+public class WaterPumpDevice extends Device {
+
+ @Schema(description = "LoRa MAC地址")
+ public String loraMac;
+
+ public WaterPumpDevice() {
+ this.type = DeviceEnum.WATER_PUMP.getValue();
+ }
+}
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/config/SnowMachineDeviceParams.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/config/SnowMachineDeviceParams.java
new file mode 100644
index 0000000..3d77c95
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/config/SnowMachineDeviceParams.java
@@ -0,0 +1,28 @@
+package com.ski.lichuan.model.device.config;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "造雪机设备参数")
+public class SnowMachineDeviceParams {
+
+ // 工作模式 关1/开2/自动3
+ @Schema(description = "工作模式 关1/开2/自动3")
+ public Integer workMode;
+ // 优先级 1-5
+ @Schema(description = "优先级 1-5")
+ public Integer priority;
+ // 雪质 1-5
+ @Schema(description = "雪质 1-5")
+ public Integer snowQuality;
+ // 启动温度 -5.0 ~ 5.0
+ @Schema(description = "启动温度 -5.0 ~ 5.0")
+ public Double startTemperature;
+ // 停止温度 -5.0 ~ 5.0
+ @Schema(description = "停止温度 -5.0 ~ 5.0")
+ public Double stopTemperature;
+ // 流量调节 0 ~ 50
+ @Schema(description = "流量调节 0 ~ 50")
+ public Integer flowAdjustment;
+}
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/config/SnowMachineDevicePitchHorizontalParams.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/config/SnowMachineDevicePitchHorizontalParams.java
new file mode 100644
index 0000000..5fa1d1c
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/device/config/SnowMachineDevicePitchHorizontalParams.java
@@ -0,0 +1,21 @@
+package com.ski.lichuan.model.device.config;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "造雪机俯仰水平控制参数")
+public class SnowMachineDevicePitchHorizontalParams {
+
+
+ // 雪机工作模式 关1/开2/自动3
+ @Schema(description = "工作模式 关1/开2/自动3")
+ public Integer workMode;
+ // 俯仰工作模式 关1/开2/自动3
+ @Schema(description = "俯仰工作模式 关1/开2/自动3")
+ public Integer pitchWorkMode;
+ // 水平工作模式 关1/开2/自动3
+ @Schema(description = "水平工作模式 关1/开2/自动3")
+ public Integer horizontalWorkMode;
+
+}
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/log/DeviceWarningRecord.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/log/DeviceWarningRecord.java
new file mode 100644
index 0000000..2d157f3
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/log/DeviceWarningRecord.java
@@ -0,0 +1,21 @@
+package com.ski.lichuan.model.log;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+@Schema(description = "设备警告记录")
+public class DeviceWarningRecord {
+ @Schema(description = "警告记录ID")
+ public Integer id;
+ @Schema(description = "警告记录内容")
+ public String content;
+ @Schema(description = "警告记录类型")
+ public String warningType;
+ @Schema(description = "警告记录设备")
+ public String warningDevice;
+ @Schema(description = "警告记录时间")
+ public LocalDateTime warningTime;
+}
diff --git a/ski-dashboard-model/src/main/java/com/ski/lichuan/model/log/OperationRecord.java b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/log/OperationRecord.java
new file mode 100644
index 0000000..b6ea403
--- /dev/null
+++ b/ski-dashboard-model/src/main/java/com/ski/lichuan/model/log/OperationRecord.java
@@ -0,0 +1,23 @@
+package com.ski.lichuan.model.log;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+@Schema(description = "操作记录")
+public class OperationRecord {
+
+ @Schema(description = "操作记录ID")
+ public Integer id;
+ @Schema(description = "操作记录操作人")
+ public String operator;
+ @Schema(description = "操作记录内容")
+ public String content;
+ @Schema(description = "操作记录类型")
+ public String operationType;
+ @Schema(description = "操作记录时间")
+ public LocalDateTime operationTime;
+
+}
diff --git a/ski-dashboard-model/src/main/resources/mapper/SnowMachineMapper.xml b/ski-dashboard-model/src/main/resources/mapper/SnowMachineMapper.xml
new file mode 100644
index 0000000..919ecd7
--- /dev/null
+++ b/ski-dashboard-model/src/main/resources/mapper/SnowMachineMapper.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO snow_machine (name, lora) VALUES (#{name}, #{lora})
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UPDATE snow_machine SET name = #{name} WHERE id = #{id}
+
+
+
+
+ UPDATE snow_machine SET name = #{name}, lora = #{lora} WHERE id = #{id}
+
+
+
+
+ DELETE FROM snow_machine WHERE id = #{id}
+
+
+
+
+ INSERT INTO snow_machine (id, name, lora) VALUES (#{id}, #{name}, #{lora})
+
+
\ No newline at end of file
diff --git a/ski-dashboard-model/src/main/resources/mapper/TrailPositionMapper.xml b/ski-dashboard-model/src/main/resources/mapper/TrailPositionMapper.xml
new file mode 100644
index 0000000..48bec6e
--- /dev/null
+++ b/ski-dashboard-model/src/main/resources/mapper/TrailPositionMapper.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO trail_position (trail_id, position, name)
+ VALUES (#{trailId}, #{position}, #{name})
+
+
+
+ UPDATE trail_position
+ SET trail_id = #{trailId}, position = #{position}, name = #{name}
+ WHERE id = #{id}
+
+
+
+ UPDATE trail_position
+ SET snow_machine_status = 0, snow_machine_id = NULL
+ WHERE id = #{id}
+
+
+
+ UPDATE trail_position
+ SET snow_machine_id = #{snowMachineId}
+ WHERE id = #{id}
+
+
+
+
+
+
+
+ UPDATE trail_position
+ SET snow_machine_status = 0, snow_machine_id = NULL
+ WHERE id NOT IN
+
+ #{id}
+
+
+
+
\ No newline at end of file
diff --git a/ski-dashboard-service/pom.xml b/ski-dashboard-service/pom.xml
index dfcf4ce..8ae20ff 100644
--- a/ski-dashboard-service/pom.xml
+++ b/ski-dashboard-service/pom.xml
@@ -9,7 +9,6 @@
0.0.1-SNAPSHOT
- com.ski.lichuan
ski-dashboard-service
@@ -17,6 +16,35 @@
21
UTF-8
+
+
+
+
+ thingsboard
+ ThingsBoard Repository
+ https://repo.thingsboard.io/artifactory/libs-release-public
+
+ true
+
+
+ true
+
+
+
+
+ aliyunmaven
+ aliyunmaven
+ https://maven.aliyun.com/repository/public
+ default
+
+ true
+
+
+ true
+
+
+
+
com.ski
@@ -25,11 +53,55 @@
compile
- com.ski.lichuan
+ com.ski
ski-dashboard-common
0.0.1-SNAPSHOT
compile
+
+ org.thingsboard
+ rest-client
+ 4.2.1
+
+
+
+ aliyunmaven
+ aliyunmaven
+ https://maven.aliyun.com/repository/public
+ default
+
+ true
+
+
+ true
+
+
+
+ thingsboard
+ ThingsBoard Repository
+ https://repo.thingsboard.io/artifactory/libs-release-public
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/ski-dashboard-service/src/main/java/com/ski/lichuan/Demo.java b/ski-dashboard-service/src/main/java/com/ski/lichuan/Demo.java
new file mode 100644
index 0000000..0c92947
--- /dev/null
+++ b/ski-dashboard-service/src/main/java/com/ski/lichuan/Demo.java
@@ -0,0 +1,119 @@
+package com.ski.lichuan;
+
+import org.thingsboard.rest.client.RestClient;
+import org.thingsboard.server.common.data.Dashboard;
+import org.thingsboard.server.common.data.DashboardInfo;
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.page.PageData;
+import org.thingsboard.server.common.data.page.PageLink;
+import org.thingsboard.server.common.data.query.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Demo {
+
+ public static void main(String[] args) {
+
+ List devicesList = getDevices();
+// List dashboardsList = getDashboards();
+ for (Device device : devicesList) {
+ if (!device.getName().equals("iot_snowmaker_m005")) {
+ continue;
+ }
+ System.out.println("找到指定设备");
+ getDataByDevice(device);
+ }
+ }
+
+ /**
+ * 获取ThingsBoard客户端
+ * @return
+ */
+ public static List getDevices() {
+
+ String url = "https://tb.ski.bkiiot.com";
+ String username = "tenant@thingsboard.org";
+ String password = "tenant";
+
+ List devicesList = new ArrayList<>();
+
+ RestClient client = new RestClient(url);
+ client.login(username, password);
+
+ PageData devices;
+ PageLink pageLink = new PageLink(10);
+ do {
+ devices = client.getTenantDevices("", pageLink);
+ devices.getData().forEach(System.out::println);
+ devicesList.addAll(devices.getData());
+ pageLink = pageLink.nextPageLink();
+ } while (devices.hasNext());
+ client.logout();
+ client.close();
+ return devicesList;
+ }
+
+ /**
+ * 获取仪表盘
+ */
+ public static List getDashboards() {
+
+ String url = "https://tb.ski.bkiiot.com";
+ String username = "tenant@thingsboard.org";
+ String password = "tenant";
+ List dashboardsList = new ArrayList<>();
+
+ RestClient client = new RestClient(url);
+ client.login(username, password);
+ PageData dashboards;
+ PageLink pageLink = new PageLink(10);
+ do {
+ dashboards = client.getTenantDashboards(pageLink);
+ dashboards.getData().forEach(System.out::println);
+ dashboardsList.addAll(dashboards.getData());
+ pageLink = pageLink.nextPageLink();
+ } while (dashboards.hasNext());
+ client.logout();
+ client.close();
+ return dashboardsList;
+
+ }
+
+ /**
+ * 获取设备属性
+ */
+ public static void getDeviceAttributes(Device device) {
+
+ String url = "https://tb.ski.bkiiot.com";
+ String username = "tenant@thingsboard.org";
+ String password = "tenant";
+
+ RestClient client = new RestClient(url);
+ client.login(username, password);
+ // 获取属性
+ List keys = client.getAttributeKeys(device.getId());
+ client.getAttributeKvEntries(device.getId(), keys).forEach(System.out::println);
+ }
+
+ /**
+ * 获取设备数据
+ */
+ public static void getDataByDevice(Device device) {
+ String url = "https://tb.ski.bkiiot.com";
+ String username = "tenant@thingsboard.org";
+ String password = "tenant";
+
+ RestClient client = new RestClient(url);
+ client.login(username, password);
+
+ client.getLatestTimeseries(device.getId(), List.of()).forEach(System.out::println);
+
+ client.logout();
+ client.close();
+
+
+ }
+
+}
diff --git a/ski-dashboard-service/src/main/java/com/ski/lichuan/initializer/AdminUserInitializer.java b/ski-dashboard-service/src/main/java/com/ski/lichuan/initializer/AdminUserInitializer.java
index ce02fe3..203635e 100644
--- a/ski-dashboard-service/src/main/java/com/ski/lichuan/initializer/AdminUserInitializer.java
+++ b/ski-dashboard-service/src/main/java/com/ski/lichuan/initializer/AdminUserInitializer.java
@@ -1,13 +1,16 @@
package com.ski.lichuan.initializer;
+import com.ski.lichuan.common.utils.MD5Util;
import com.ski.lichuan.mapper.UserMapper;
import com.ski.lichuan.model.auth.SysUser;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;
@Component
+@Slf4j
public class AdminUserInitializer implements CommandLineRunner {
@Autowired
@@ -24,15 +27,16 @@ public class AdminUserInitializer implements CommandLineRunner {
// 创建默认管理员用户
SysUser adminUser = new SysUser();
adminUser.setUsername("admin");
- // 默认密码为 admin123,实际使用时应修改为更安全的密码
- adminUser.setPassword(passwordEncoder.encode("admin123"));
+ // 默认密码为 123456,实际使用时应修改为更安全的密码 使用MD5加密
+ String text = MD5Util.encrypt("123456");
+ adminUser.setPassword(passwordEncoder.encode(text));
adminUser.setNickname("系统管理员");
adminUser.setStatus(1); // 启用状态
// 插入用户到数据库
userMapper.insertUser(adminUser);
- System.out.println("默认管理员用户已创建,用户名: admin, 密码: admin123 (请登录后及时修改密码)");
+ log.info("默认管理员用户已创建,用户名: admin, 密码: 123456 (请登录后及时修改密码)");
} else {
- System.out.println("管理员用户已存在");
+ log.info("管理员用户已存在");
}
}
}
\ No newline at end of file
diff --git a/ski-dashboard-service/src/main/java/com/ski/lichuan/initializer/TrailInitializer.java b/ski-dashboard-service/src/main/java/com/ski/lichuan/initializer/TrailInitializer.java
new file mode 100644
index 0000000..fae654a
--- /dev/null
+++ b/ski-dashboard-service/src/main/java/com/ski/lichuan/initializer/TrailInitializer.java
@@ -0,0 +1,53 @@
+package com.ski.lichuan.initializer;
+
+import com.ski.lichuan.mapper.TrailPositionMapper;
+import com.ski.lichuan.model.dashboard.TrailPosition;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+
+import java.util.List;
+
+@Slf4j
+public class TrailInitializer implements CommandLineRunner {
+
+ @Autowired
+ private TrailPositionMapper trailPositionMapper;
+
+ @Override
+ public void run(String... args) throws Exception {
+ List trailPositions = trailPositionMapper.selectAll();
+ if (trailPositions.isEmpty()) {
+ log.info("数据库中不存在坑位数据,开始初始化...");
+ Integer[][] positions = {
+ {1, 1},
+ {1, 2},
+ {1, 3},
+ {1, 4},
+ {2, 1},
+ {2, 2},
+ {2, 3},
+ {2, 4},
+ {2, 5},
+ {2, 6},
+ {3, 1},
+ {3, 2},
+ {3, 3},
+ {3, 4},
+ {3, 5},
+ {3, 6},
+ {4, 1},
+ {4, 2},
+ {4, 3}
+ };
+
+ for (Integer[] position : positions) {
+ TrailPosition trailPosition = new TrailPosition();
+ trailPosition.setTrailId(position[0]);
+ trailPosition.setPosition(position[1]);
+ trailPosition.setName(position[0] + "-" + position[1]);
+ trailPositionMapper.insert(trailPosition);
+ }
+ }
+ }
+}
diff --git a/ski-dashboard-service/src/main/java/com/ski/lichuan/services/DeviceDataPollingService.java b/ski-dashboard-service/src/main/java/com/ski/lichuan/services/DeviceDataPollingService.java
new file mode 100644
index 0000000..7660e71
--- /dev/null
+++ b/ski-dashboard-service/src/main/java/com/ski/lichuan/services/DeviceDataPollingService.java
@@ -0,0 +1,177 @@
+package com.ski.lichuan.services;
+
+import com.ski.lichuan.model.dashboard.TrailPosition;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.thingsboard.rest.client.RestClient;
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.page.PageData;
+import org.thingsboard.server.common.data.page.PageLink;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class DeviceDataPollingService {
+
+ // 高优先级查询列表(造雪机)
+ public static final List HIGH_PRIORITY_SNOWMACHINE_IDS = Arrays.asList();
+ // 高优先级查询列表(水泵)
+ public static final List HIGH_PRIORITY_PUMP_IDS = Arrays.asList();
+ @Value("${thingsboard.client.url:https://tb.ski.bkiiot.com}")
+ private String clientUrl;
+ @Value("${thingsboard.client.username:tenant@thingsboard.org}")
+ private String clientUsername;
+ @Value("${thingsboard.client.password:tenant}")
+ private String clientPassword;
+ // 客户端
+ private RestClient client;
+
+ @Autowired
+ private TrailPositionService trailPositionService;
+
+ @Autowired
+ private SnowMachineDeviceService snowMachineDeviceService;
+
+ /**
+ * 定时轮询设备状态
+ */
+ @Scheduled(fixedRate = 60000)
+ public void pollDeviceStatus() {
+ /**
+ * 核心逻辑:每60秒轮询一次所有设备状态,查询所有坑位上的雪机和水泵的状态
+ */
+
+ }
+
+
+ /**
+ * 定时轮询设备数据
+ * 每15秒执行一次
+ */
+ @Scheduled(fixedRate = 15000)
+ public void pollDeviceData() {
+ /**
+ * 核心逻辑:每15秒轮询一次所有设备数据,查询所有坑位上的雪机和水泵的状态
+ */
+
+ }
+
+ /**
+ * 定时轮询设备列表(造雪机、水泵)
+ * 每120秒执行一次
+ */
+ @Scheduled(fixedRate = 120000)
+ public void pollDevices() {
+ /**
+ * 核心逻辑:每120秒轮询一次所有设备列表,更新造雪机设备和水泵
+ */
+ log.info("开始查询设备列表");
+ List devices = getDevices();
+
+ List trailPositions = trailPositionService.getAllTrailPositionList();
+ // 转为Map,方便查询 (TrailId,Position) -> TrailPosition
+ Map trailPositionMap = trailPositions.stream()
+ .collect(Collectors.toMap(trailPosition -> trailPosition.getTrailId() * 10000 + trailPosition.getPosition(), trailPosition -> trailPosition));
+
+ for (Device device : devices) {
+ //s-{id}-{trailId}-{position}-{disable}
+ if (device.getLabel() != null && device.getLabel().startsWith("s-")) {
+ String[] parts = device.getLabel().split("-");
+ if (parts.length < 3) {
+ // 异常的设备
+ log.warn("异常的造雪机设备标签格式:{}", device.getLabel());
+ continue;
+ }
+ if (parts.length >= 4 && "disable".equals(parts[3])) {
+ // 禁用状态,跳过
+ log.info("造雪机设备 {} 已禁用,跳过", device.getLabel());
+ continue;
+ }
+ // 说明是造雪机设备
+ String id = parts[1];
+ String trailId = parts[2];
+ String position = parts[3];
+
+ // 判断是数字
+ if (!trailId.matches("\\d+") || !position.matches("\\d+")) {
+ // 不是数字,跳过
+ log.warn("造雪机设备 {} 标签格式错误,跳过", device.getLabel());
+ continue;
+ }
+ // id 不为空
+ if (id.isEmpty()) {
+ // 空id,跳过
+ log.warn("造雪机设备 {} 标签格式错误,跳过", device.getLabel());
+ continue;
+ }
+
+ Integer idValue = Integer.parseInt(id);
+ Integer trailIdValue = Integer.parseInt(trailId);
+ Integer positionValue = Integer.parseInt(position);
+
+ // 更新雪机信息
+ String name = device.getName() != null ? device.getName() : "雪机" + trailId + position;
+ try {
+ snowMachineDeviceService.updateSnowMachineDeviceNameAndLora(idValue, name, device.getId().toString());
+ log.info("更新造雪机设备信息 {} 成功", device.getLabel());
+ } catch (Exception e) {
+ log.error("更新造雪机设备信息 {} 失败:{}", device.getLabel(), e.getMessage());
+ }
+
+ // 检查是否存在对应的雪道位置
+ TrailPosition trailPosition = trailPositionMap.get(trailIdValue * 10000 + positionValue);
+ if (trailPosition == null) {
+ // 雪道位置不存在,跳过
+ log.warn("造雪机设备 {} 对应的雪道位置不存在,跳过", device.getLabel());
+ continue;
+ }
+
+ // 更新雪道位置的造雪机ID
+ trailPosition.setSnowMachineId(idValue);
+ trailPositionService.updateTrailPositionSnowMachineId(trailPosition.getId(), idValue);
+ // 从Map中删除该雪道位置,防止重复处理
+ trailPositionMap.remove(trailIdValue * 10000 + positionValue);
+
+ }
+ }
+
+ // 清楚Map中剩余的雪道位置
+ List mapIdList = trailPositionMap.values().stream().map(TrailPosition::getId).collect(Collectors.toList());
+ try {
+ trailPositionService.clearTrailPositionSnowMachineIdBatch(mapIdList);
+ } catch (Exception e) {
+ log.error("清除雪道位置 {} 造雪机ID失败:{}", mapIdList, e.getMessage());
+ }
+ }
+
+ private RestClient getClient() {
+ if (client == null) {
+ client = new RestClient(clientUrl);
+ client.login(clientUsername, clientPassword);
+ }
+ return client;
+ }
+
+ public List getDevices() {
+ RestClient client = getClient();
+ List devicesList = new ArrayList<>();
+
+ PageData devices;
+ PageLink pageLink = new PageLink(10);
+ do {
+ devices = client.getTenantDevices("", pageLink);
+ devices.getData().forEach(device -> log.info("获取到的造雪机设备:{}", device));
+ devicesList.addAll(devices.getData());
+ pageLink = pageLink.nextPageLink();
+ } while (devices.hasNext());
+ return devicesList;
+ }
+}
\ No newline at end of file
diff --git a/ski-dashboard-service/src/main/java/com/ski/lichuan/services/IoTService.java b/ski-dashboard-service/src/main/java/com/ski/lichuan/services/IoTService.java
new file mode 100644
index 0000000..61f838a
--- /dev/null
+++ b/ski-dashboard-service/src/main/java/com/ski/lichuan/services/IoTService.java
@@ -0,0 +1,4 @@
+package com.ski.lichuan.services;
+
+public class IoTService {
+}
diff --git a/ski-dashboard-service/src/main/java/com/ski/lichuan/services/SnowMachineDeviceService.java b/ski-dashboard-service/src/main/java/com/ski/lichuan/services/SnowMachineDeviceService.java
new file mode 100644
index 0000000..627fba3
--- /dev/null
+++ b/ski-dashboard-service/src/main/java/com/ski/lichuan/services/SnowMachineDeviceService.java
@@ -0,0 +1,158 @@
+package com.ski.lichuan.services;
+
+import com.ski.lichuan.mapper.SnowMachineMapper;
+import com.ski.lichuan.model.device.Impl.SnowMachineDevice;
+import com.ski.lichuan.model.device.config.SnowMachineDeviceParams;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class SnowMachineDeviceService {
+
+ @Autowired
+ private SnowMachineMapper snowMachineMapper;
+
+ /**
+ * 新增造雪机设备
+ *
+ * @param snowMachineDevice 造雪机设备
+ * @return 新增结果
+ */
+ public int addSnowMachineDevice(SnowMachineDevice snowMachineDevice) {
+ // 检查是否已存在相同LORA地址的造雪机设备
+ if (snowMachineMapper.selectByLora(snowMachineDevice.getLora()) != null) {
+ throw new IllegalArgumentException("造雪机设备已存在相同LORA地址");
+ }
+ return snowMachineMapper.insert(snowMachineDevice);
+ }
+
+ /**
+ * 查询所有未绑定位置的造雪机设备
+ *
+ * @return 未绑定位置的造雪机设备列表
+ */
+ public List selectUnboundMachines() {
+ return snowMachineMapper.selectUnboundMachines();
+ }
+
+
+ /**
+ * 查询所有造雪机设备
+ *
+ * @return 所有造雪机设备列表
+ */
+ public List getAllSnowMachineDevices() {
+ return snowMachineMapper.selectAll();
+ }
+
+ /**
+ * 根据ID查询造雪机设备
+ *
+ * @param id 造雪机设备ID
+ * @return 造雪机设备
+ */
+ public SnowMachineDevice getSnowMachineDeviceById(Integer id) {
+ // 检查是否存在该ID的造雪机设备
+ if (snowMachineMapper.selectById(id) == null) {
+ throw new IllegalArgumentException("造雪机设备不存在");
+ }
+ return snowMachineMapper.selectById(id);
+ }
+
+ /**
+ * 根据LORA地址查询造雪机设备
+ *
+ * @param lora 造雪机设备LORA地址
+ * @return 造雪机设备
+ */
+ public SnowMachineDevice selectByLora(String lora) {
+ return snowMachineMapper.selectByLora(lora);
+ }
+ /**
+ * 统计造雪机设备数量
+ *
+ * @return 造雪机设备数量
+ */
+ public int count() {
+ return snowMachineMapper.count();
+ }
+
+ /**
+ * 更新造雪机设备名称
+ *
+ * @param snowMachineDevice 造雪机设备
+ * @return 更新结果
+ */
+ public int updateSnowMachineDevice(SnowMachineDevice snowMachineDevice) {
+ if (snowMachineMapper.selectById(snowMachineDevice.getId()) == null) {
+ throw new IllegalArgumentException("造雪机设备不存在");
+ }
+ return snowMachineMapper.updateName(snowMachineDevice);
+ }
+
+ /**
+ * 更新造雪机信息
+ *
+ * @param id 造雪机设备ID
+ * @param name 造雪机设备名称
+ * @param lora 造雪机设备LORA地址
+ * @return 更新结果
+ */
+ public int updateSnowMachineDeviceNameAndLora(Integer id, String name, String lora) {
+ // 检查是否存在该ID的造雪机设备
+ if (snowMachineMapper.selectById(id) == null) {
+ // 则新增
+ SnowMachineDevice newSnowMachineDevice = new SnowMachineDevice();
+ newSnowMachineDevice.setId(id);
+ newSnowMachineDevice.setName(name);
+ newSnowMachineDevice.setLora(lora);
+ return snowMachineMapper.insertById(newSnowMachineDevice);
+ } else {
+ // 更新造雪机设备信息
+ SnowMachineDevice snowMachineDevice = snowMachineMapper.selectById(id);
+ snowMachineDevice.setName(name);
+ snowMachineDevice.setLora(lora);
+ return snowMachineMapper.updateName(snowMachineDevice);
+ }
+ }
+
+ /**
+ * 删除造雪机设备
+ *
+ * @param id 造雪机设备ID
+ * @return 删除结果
+ */
+ public int deleteSnowMachineDevice(Integer id) {
+ return snowMachineMapper.deleteById(id);
+ }
+
+ /**
+ * 获取所有雪机设备信息
+ *
+ * @return 所有雪机设备列表
+ */
+ public List selectAllDevices() {
+ return snowMachineMapper.selectAll();
+ }
+
+ /**
+ * 群控雪机设备
+ * @param deviceList 雪机设备列表
+ * @param params 造雪机设备参数
+ * @return 群控结果
+ */
+ public boolean groupControl(List deviceList, SnowMachineDeviceParams params) {
+ // 检查是否存在该ID的造雪机设备
+ if (deviceList.isEmpty()) {
+ throw new IllegalArgumentException("造雪机设备不存在");
+ }
+ // 群控雪机设备
+ for (SnowMachineDevice device : deviceList) {
+ // 发送群控指令
+ // ...
+ }
+ return true;
+ }
+}
diff --git a/ski-dashboard-service/src/main/java/com/ski/lichuan/services/TrailPositionService.java b/ski-dashboard-service/src/main/java/com/ski/lichuan/services/TrailPositionService.java
new file mode 100644
index 0000000..b92fd52
--- /dev/null
+++ b/ski-dashboard-service/src/main/java/com/ski/lichuan/services/TrailPositionService.java
@@ -0,0 +1,310 @@
+package com.ski.lichuan.services;
+
+import com.ski.lichuan.mapper.SnowMachineMapper;
+import com.ski.lichuan.mapper.TrailPositionMapper;
+import com.ski.lichuan.model.common.DeviceEnum;
+import com.ski.lichuan.model.dashboard.*;
+import com.ski.lichuan.model.device.Impl.SnowMachineDevice;
+import com.ski.lichuan.model.device.config.SnowMachineDeviceParams;
+import com.ski.lichuan.model.device.config.SnowMachineDevicePitchHorizontalParams;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class TrailPositionService {
+
+ @Autowired
+ private TrailPositionMapper trailPositionMapper;
+
+ @Autowired
+ private SnowMachineMapper snowMachineDeviceMapper;
+
+ /**
+ * 获取所有已绑定雪机的雪道位置信息
+ */
+ public List getBoundTrailPositions() {
+ return trailPositionMapper.selectBoundPositions();
+ }
+
+ /**
+ * 获取所有未绑定雪机的雪道位置信息
+ */
+ public List getUnboundTrailPositions() {
+ return trailPositionMapper.selectUnboundPositions();
+ }
+
+ /**
+ * 获取所有雪道及位置信息
+ */
+ public List> getAllTrailPositions() {
+ List allTrailPositions = trailPositionMapper.selectAll();
+ List> result = new ArrayList<>();
+ for (int i = 1; i <= 4; i++) {
+ int finalI = i;
+ List trailPositions = allTrailPositions.stream()
+ .filter(trailPosition -> trailPosition.getTrailId().equals(finalI))
+ .collect(Collectors.toList());
+ result.add(trailPositions);
+ }
+ // 遍历result,将每个雪道的位置信息按position排序
+ for (List trailPositions : result) {
+ // 更新trailPosition状态
+ for (TrailPosition trailPosition : trailPositions) {
+ if (trailPosition.getSnowMachineStatus() == 0) {
+ // 暂时随机
+ trailPosition.setSnowMachineStatus((int) (Math.random() * 3));
+ }
+ }
+
+ trailPositions.sort((p1, p2) -> p1.getPosition().compareTo(p2.getPosition()));
+ }
+
+ return result;
+ }
+
+ /**
+ * 获取雪道位置的详细信息(造雪机)
+ */
+ public TrailPositionInfo getTrailPositionInfo(Integer id) {
+ TrailPosition trailPosition = trailPositionMapper.selectById(id);
+ if (trailPosition == null) {
+ return null;
+ } else {
+ TrailPositionInfo result = new TrailPositionInfo();
+
+ Integer trailId = id / 10;
+ Integer position = id % 10;
+
+ // 雪机设备
+ SnowMachineDevice snowMachineDevice = new SnowMachineDevice();
+ snowMachineDevice.setLora("1234567890123456");
+ snowMachineDevice.setId(1000000000 + id);
+ snowMachineDevice.setName("造雪机-" + id);
+ snowMachineDevice.setType(DeviceEnum.SNOW_MAKER.getValue());
+ // 雪道位置信息
+ trailPosition.setSnowMachineStatus(1);
+ // 雪道位置状态信息
+ TrailPositionMonitorInfo trailPositionMonitorInfo = new TrailPositionMonitorInfo();
+ trailPositionMonitorInfo.setTrailPosition(trailPosition);
+ trailPositionMonitorInfo.setSnowMakerName(snowMachineDevice.getName());
+
+ trailPositionMonitorInfo.setPriority(1);
+ trailPositionMonitorInfo.setEnvironmentTemperature(-3.5);
+ trailPositionMonitorInfo.setEnvironmentHumidity(50.0);
+ trailPositionMonitorInfo.setWetBulbTemperature(0.5);
+ trailPositionMonitorInfo.setCommunicationStatus(true);
+ trailPositionMonitorInfo.setIsNormal(true);
+ trailPositionMonitorInfo.setIsRunning(true);
+ trailPositionMonitorInfo.setTemperatureConditionSatisfied(true);
+ trailPositionMonitorInfo.setWindSpeed(5.0);
+ trailPositionMonitorInfo.setWindDirection(180.0);
+ // 造雪机设备状态
+ SnowMachineDeviceInfo snowMachineDeviceInfo = new SnowMachineDeviceInfo();
+ snowMachineDeviceInfo.setSnowMachineDevice(snowMachineDevice);
+ snowMachineDeviceInfo.setFrontWaterPressure(0.5 + Math.random() * 0.3); // 前端水压 0.5-0.8 MPa
+ snowMachineDeviceInfo.setBackWaterPressure(0.4 + Math.random() * 0.2); // 后端水压 0.4-0.6 MPa
+ snowMachineDeviceInfo.setPressure(0.8 + Math.random() * 0.2); // 气压 0.8-1.0 MPa
+ snowMachineDeviceInfo.setTemperature(2.5 + Math.random() * 2.0); // 水温 2.5-4.5 ℃
+ snowMachineDeviceInfo.setGivenAngle(45.0 + Math.random() * 10.0); // 给定开度 45-55°
+ snowMachineDeviceInfo.setActualAngle(44.0 + Math.random() * 12.0); // 实际开度 44-56°
+ snowMachineDeviceInfo.setIsNormal(Math.random() > 0.1); // 是否正常 90%概率正常
+ snowMachineDeviceInfo.setMode((int) (Math.random() * 3) + 1); // 模式 1-3随机
+ snowMachineDeviceInfo.setCompressorStatus((int) (Math.random() * 2) + 1); // 空压机状态 1-2随机
+ snowMachineDeviceInfo.setFanStatus((int) (Math.random() * 2) + 1); // 风机状态 1-2随机
+ snowMachineDeviceInfo.setHeatingRingStatus((int) (Math.random() * 2) + 1); // 加热环状态 1-2随机
+ snowMachineDeviceInfo.setValveStatus((int) (Math.random() * 2) + 1); // 电磁阀状态1 1-2随机
+ snowMachineDeviceInfo.setValveStatus2((int) (Math.random() * 2) + 1); // 电磁阀状态2 1-2随机
+ snowMachineDeviceInfo.setValveStatus3((int) (Math.random() * 2) + 1); // 电磁阀状态3 1-2随机
+ snowMachineDeviceInfo.setPitchMode((int) (Math.random() * 3) + 1); // 俯仰模式 1-3随机
+ snowMachineDeviceInfo.setPitchAngle(15.0 + Math.random() * 20.0); // 俯仰角度 15-35°
+ snowMachineDeviceInfo.setPitchStatus((int) (Math.random() * 2) + 1); // 俯仰状态 1-2随机
+ snowMachineDeviceInfo.setYawMode((int) (Math.random() * 3) + 1); // 摆头模式 1-3随机
+ snowMachineDeviceInfo.setYawAngle(30.0 + Math.random() * 40.0); // 摆头角度 30-70°
+ snowMachineDeviceInfo.setYawStatus((int) (Math.random() * 2) + 1); // 摆头状态 1-2随机
+ // 造雪机配置
+ SnowMachineDeviceParams snowMakerDeviceParams = new SnowMachineDeviceParams();
+ snowMakerDeviceParams.setWorkMode((int) (Math.random() * 3) + 1); // 工作模式 1-3随机
+ snowMakerDeviceParams.setPriority((int) (Math.random() * 5) + 1); // 优先级 1-5随机
+ snowMakerDeviceParams.setSnowQuality((int) (Math.random() * 5) + 1); // 雪质 1-5随机
+ snowMakerDeviceParams.setStartTemperature(-5.0 + Math.random() * 10.0); // 启动温度 -5.0 ~ 5.0
+ snowMakerDeviceParams.setStopTemperature(-5.0 + Math.random() * 10.0); // 停止温度 -5.0 ~ 5.0
+ snowMakerDeviceParams.setFlowAdjustment((int) (Math.random() * 50)); // 流量调节 0 ~ 50
+
+ // 数据统计
+ TrailPositionStatisticsInfo trailPositionStatisticsInfo = new TrailPositionStatisticsInfo();
+ trailPositionStatisticsInfo.setRunningDuration(120.5 + Math.random() * 100.0); // 运行时长 120.5-220.5分钟
+ trailPositionStatisticsInfo.setFlowStatistics(1000.0 + Math.random() * 500.0); // 流量统计 1000-1500 L/H
+ trailPositionStatisticsInfo.setSnowArea(500.0 + Math.random() * 300.0); // 造雪面积 500-800 平方米
+
+ result.setTrailPositionMonitorInfo(trailPositionMonitorInfo);
+ result.setSnowMakerInfo(snowMachineDeviceInfo);
+ result.setSnowMakerDeviceParams(snowMakerDeviceParams);
+ result.setTrailPositionStatisticsInfo(trailPositionStatisticsInfo);
+
+ return result;
+ }
+
+ }
+
+
+ /**
+ * 关联造雪机设备
+ */
+ public boolean connectDevice(Integer trailPositionId, Integer deviceId) {
+ TrailPosition trailPosition = trailPositionMapper.selectById(trailPositionId);
+ if (trailPosition == null) {
+ return false;
+ }
+ SnowMachineDevice snowMachineDevice = snowMachineDeviceMapper.selectById(deviceId);
+ if (snowMachineDevice == null) {
+ return false;
+ }
+ trailPosition.setSnowMachineId(deviceId);
+ trailPosition.setSnowMachineStatus(1);
+ trailPositionMapper.updateSnowMachine(trailPositionId, trailPosition.getSnowMachineId());
+ return true;
+ }
+
+ /**
+ * 取消关联造雪机设备
+ */
+ public boolean disconnectDevice(Integer trailPositionId) {
+ TrailPosition trailPosition = trailPositionMapper.selectById(trailPositionId);
+ if (trailPosition == null) {
+ return false;
+ }
+ trailPosition.setSnowMachineId(null);
+ trailPosition.setSnowMachineStatus(0);
+ trailPositionMapper.clearSnowMachine(trailPositionId);
+ return true;
+ }
+
+ /**
+ * 群控造雪机设备
+ *
+ * @param trailPositionIds 雪道位置ID列表
+ * @param params 造雪机设备参数
+ * @return 群控结果
+ */
+ public boolean groupControl(List trailPositionIds, SnowMachineDeviceParams params) {
+ // 检查是否存在该ID的造雪机设备
+ if (trailPositionIds.isEmpty()) {
+ throw new IllegalArgumentException("雪道位置不存在");
+ }
+ // 反查造雪机设备ID
+ List deviceIds = trailPositionMapper.selectDeviceIdsByTrailPositionIds(trailPositionIds);
+ if (deviceIds.isEmpty()) {
+ throw new IllegalArgumentException("造雪机设备不存在");
+ }
+ // 群控雪机设备
+ for (Integer deviceId : deviceIds) {
+ // 发送群控指令
+ // ...
+ }
+ return true;
+ }
+
+
+ /**
+ * 俯仰水平控制
+ *
+ * @param trailPositionId 雪道位置ID
+ * @param params 俯仰水平参数
+ * @return 控制结果
+ */
+ public Boolean pitchHorizontalControl(Integer trailPositionId, SnowMachineDevicePitchHorizontalParams params) {
+ // 检查是否存在该ID的造雪机设备
+ TrailPosition trailPosition = trailPositionMapper.selectById(trailPositionId);
+ if (trailPosition == null) {
+ throw new IllegalArgumentException("雪道位置不存在");
+ }
+ // 反查造雪机设备ID
+ SnowMachineDevice snowMachineDevice = snowMachineDeviceMapper.selectById(trailPosition.getSnowMachineId());
+ if (snowMachineDevice == null) {
+ throw new IllegalArgumentException("造雪机设备不存在");
+ }
+
+ // 发送俯仰水平控制指令
+ // ...
+ return true;
+ }
+
+ /**
+ * 保存造雪机参数
+ *
+ * @param trailPosition 雪道位置ID
+ * @param params 造雪机设备参数
+ * @return 保存结果
+ */
+ public Boolean saveSnowMakerDeviceParams(Integer trailPosition, SnowMachineDeviceParams params) {
+ // 检查是否存在该ID的造雪机设备
+ TrailPosition trailPositionEntity = trailPositionMapper.selectById(trailPosition);
+ if (trailPositionEntity == null) {
+ throw new IllegalArgumentException("雪道位置不存在");
+ }
+ // 反查造雪机设备ID
+ SnowMachineDevice snowMachineDevice = snowMachineDeviceMapper.selectById(trailPositionEntity.getSnowMachineId());
+ if (snowMachineDevice == null) {
+ throw new IllegalArgumentException("造雪机设备不存在");
+ }
+ // 保存造雪机参数
+ // ...
+ return true;
+ }
+
+ /**
+ * 更新雪道坑位雪机信息
+ *
+ * @param trailPositionId 雪道位置ID
+ * @param snowMachineId 造雪机设备ID
+ * @return 更新结果
+ */
+ public Boolean updateTrailPositionSnowMachineId(Integer trailPositionId, Integer snowMachineId) {
+ // 检查是否存在该ID的雪道位置
+ TrailPosition trailPosition = trailPositionMapper.selectById(trailPositionId);
+ if (trailPosition == null) {
+ throw new IllegalArgumentException("雪道位置不存在");
+ }
+ // 更新雪道位置雪机信息
+ trailPosition.setSnowMachineId(snowMachineId);
+ trailPositionMapper.updateSnowMachine(trailPositionId, snowMachineId);
+ return true;
+ }
+
+ /**
+ * 清空雪道位置雪机信息
+ *
+ * @param trailPositionIds 雪道位置ID列表
+ * @return 更新结果
+ */
+ public Boolean clearTrailPositionSnowMachineIdBatch(List trailPositionIds) {
+ // 检查是否存在该ID的雪道位置
+ if (trailPositionIds.isEmpty()) {
+ throw new IllegalArgumentException("雪道位置不存在");
+ }
+ // 清空雪道位置雪机信息
+ for (Integer trailPositionId : trailPositionIds) {
+ TrailPosition trailPosition = trailPositionMapper.selectById(trailPositionId);
+ if (trailPosition == null) {
+ throw new IllegalArgumentException("雪道位置不存在");
+ }
+ trailPosition.setSnowMachineId(null);
+ trailPosition.setSnowMachineStatus(0);
+ trailPositionMapper.clearSnowMachine(trailPositionId);
+ }
+ return true;
+ }
+
+ /**
+ * 平铺返回所有雪道位置信息
+ *
+ * @return 所有雪道位置信息列表
+ */
+ public List getAllTrailPositionList() {
+ return trailPositionMapper.selectAll();
+ }
+}
diff --git a/ski-dashboard-service/src/main/resources/sql/sys_user.sql b/ski-dashboard-service/src/main/resources/sql/sys_user.sql
index 369c618..dcd3ecb 100644
--- a/ski-dashboard-service/src/main/resources/sql/sys_user.sql
+++ b/ski-dashboard-service/src/main/resources/sql/sys_user.sql
@@ -10,4 +10,33 @@ CREATE TABLE sys_user (
COMMENT ON COLUMN sys_user.username IS '用户名';
COMMENT ON COLUMN sys_user.password IS '加密后的密码(BCrypt)';
COMMENT ON COLUMN sys_user.nickname IS '昵称';
-COMMENT ON COLUMN sys_user.status IS '状态(1-正常,0-禁用)';
\ No newline at end of file
+COMMENT ON COLUMN sys_user.status IS '状态(1-正常,0-禁用)';
+
+CREATE TABLE snow_machine (
+ id BIGSERIAL PRIMARY KEY,
+ type SMALLINT DEFAULT 1,
+ name VARCHAR(255),
+ lora VARCHAR(255),
+ CONSTRAINT uk_lora UNIQUE (lora)
+);
+
+COMMENT ON COLUMN snow_machine.type IS '类型1雪机2水泵';
+COMMENT ON COLUMN snow_machine.name IS '名称';
+COMMENT ON COLUMN snow_machine.lora IS 'Lora 地址';
+
+CREATE TABLE trail_position (
+ id BIGSERIAL PRIMARY KEY,
+ trail_id BIGINT NOT NULL,
+ position SMALLINT,
+ trail_name VARCHAR(255),
+ snow_machine_id BIGINT,
+ snow_machine_status SMALLINT DEFAULT 0,
+);
+
+COMMENT ON COLUMN trail_position.trail_id IS '雪道ID';
+COMMENT ON COLUMN trail_position.position IS '位置';
+COMMENT ON COLUMN trail_position.trail_name IS '雪道名称';
+COMMENT ON COLUMN trail_position.snow_machine_id IS '雪机ID';
+COMMENT ON COLUMN trail_position.snow_machine_status IS '雪机状态 0无 1正常 2停止';
+
+
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
deleted file mode 100644
index f1f6fbd..0000000
--- a/src/main/resources/application.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-spring.application.name=ski-dashboard
-# ??????? postgresql
-spring.datasource.url=jdbc:postgresql://localhost:5432/ski_dashboard
-spring.datasource.username=postgres
-spring.datasource.password=tanlifan
-
-JWT_SECRET=vf4JZhcyfdK7tJs0GZ3Qjf0dSv4BId9ITjsM2fol26gOBxM17nUySiMcV0Lo2u0Y