Compare commits
56 Commits
dev_bak_04
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 521e3e4e24 | |||
| dfdf575932 | |||
| 922d30632b | |||
| ecda2b0ebc | |||
| 152cae0323 | |||
| 9f462e41fc | |||
| 6aaed4dacc | |||
| 885e94883b | |||
| 710f33d882 | |||
| 659073db03 | |||
| 736c510270 | |||
| 46fb4fecde | |||
| fb830f77ea | |||
| 9ae4334421 | |||
| ac35fd229b | |||
| 2d338d259b | |||
| 707baaefb0 | |||
| 0f36d8b4d1 | |||
| db17d50ef6 | |||
| 6d39c4296e | |||
| 87d691f927 | |||
| fe68120f71 | |||
| 5ea88ddb99 | |||
| 08099e2eda | |||
| 4d3375fc5b | |||
| b7c1edf68f | |||
| 2a47794a13 | |||
| d34bafba98 | |||
| b17ade54a1 | |||
| fdd6019a77 | |||
| 33507dc475 | |||
| 9125dbc2b9 | |||
| be8b306eef | |||
| 43e491c0b6 | |||
| f57c9b9dda | |||
| 05b90f8dc3 | |||
| c1fe2c582d | |||
| 4229b07f63 | |||
| 68b2698614 | |||
| 8e4c122f9a | |||
| 065c21b038 | |||
| 218be8e008 | |||
| 39ea145367 | |||
| 527b099f2c | |||
| 6be70e78c8 | |||
| 4e5c17d59f | |||
| 79da694baf | |||
| 3000531ca9 | |||
| 7d7c471b39 | |||
| 3868194932 | |||
| 0dbed4006c | |||
| 37d800be69 | |||
| 722e8a6ba7 | |||
| fee5d2efb9 | |||
|
|
3170e86716 | ||
|
|
a1c3040210 |
50
Dockerfile
Normal file
50
Dockerfile
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# ====================== 构建阶段 ======================
|
||||||
|
FROM maven:3.9.9-eclipse-temurin-8 AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 缓存pom
|
||||||
|
COPY pom.xml .
|
||||||
|
COPY cmvr-iot-admin/pom.xml cmvr-iot-admin/
|
||||||
|
COPY cmvr-iot-framework/pom.xml cmvr-iot-framework/
|
||||||
|
COPY cmvr-iot-system/pom.xml cmvr-iot-system/
|
||||||
|
COPY cmvr-iot-quartz/pom.xml cmvr-iot-quartz/
|
||||||
|
COPY cmvr-iot-generator/pom.xml cmvr-iot-generator/
|
||||||
|
COPY cmvr-iot-common/pom.xml cmvr-iot-common/
|
||||||
|
COPY cmvr-iot-device/pom.xml cmvr-iot-device/
|
||||||
|
COPY cmvr-iot-test/pom.xml cmvr-iot-test/
|
||||||
|
COPY cmvr-iot-api/pom.xml cmvr-iot-api/
|
||||||
|
COPY cmvr-iot-vi/pom.xml cmvr-iot-vi/
|
||||||
|
COPY cmvr-iot-ti/pom.xml cmvr-iot-ti/
|
||||||
|
COPY cmvr-iot-evaluation/pom.xml cmvr-iot-evaluation/
|
||||||
|
COPY cmvr-iot-api/cmvr-iot-llm/pom.xml cmvr-iot-api/cmvr-iot-llm/
|
||||||
|
COPY cmvr-iot-api/cmvr-iot-edge/pom.xml cmvr-iot-api/cmvr-iot-edge/
|
||||||
|
COPY cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/pom.xml cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/
|
||||||
|
COPY cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/pom.xml cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/
|
||||||
|
|
||||||
|
RUN mvn dependency:go-offline -B --no-transfer-progress
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN mvn clean package -DskipTests -pl cmvr-iot-admin -am --no-transfer-progress
|
||||||
|
|
||||||
|
# ====================== 运行阶段 ======================
|
||||||
|
FROM openjdk:8-jdk-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# -------------------------- 【唯一正确写法】 --------------------------
|
||||||
|
# 1. 先把所有jar复制进来
|
||||||
|
COPY --from=builder /app/cmvr-iot-admin/target/*.jar ./
|
||||||
|
|
||||||
|
# 2. 自动删除不能运行的小jar(只保留可执行jar)
|
||||||
|
RUN find . -name "*.jar" -type f -size -20000k -delete
|
||||||
|
|
||||||
|
# 3. 重命名为app.jar
|
||||||
|
RUN mv *.jar app.jar
|
||||||
|
|
||||||
|
ENTRYPOINT ["java", "-jar", \
|
||||||
|
"-Dspring.profiles.active=dev", \
|
||||||
|
"-Djava.security.egd=file:/dev/./urandom", \
|
||||||
|
"-XX:+UseG1GC", \
|
||||||
|
"-Xms512m", "-Xmx1024m", \
|
||||||
|
"app.jar"]
|
||||||
249
README.md
Normal file
249
README.md
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
# cmvr-iot
|
||||||
|
|
||||||
|
cmvr-iot 是一个基于 Java 8 和 Spring Boot 2.5 的多模块后端工程,提供设备管理、边缘机器人控制、测试编排、巡检、TTS、AIMA、VI/TI 等业务能力。工程入口在 `cmvr-iot-admin`,其余模块按业务和基础能力拆分。
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- Java 8
|
||||||
|
- Spring Boot 2.5.15
|
||||||
|
- Spring Security
|
||||||
|
- MyBatis Plus / MyBatis Plus Join
|
||||||
|
- MySQL / Redis
|
||||||
|
- Druid
|
||||||
|
- Quartz
|
||||||
|
- Knife4j / Swagger
|
||||||
|
- gRPC Java 1.58.0
|
||||||
|
- Protobuf / protoc-maven-plugin
|
||||||
|
- MinIO
|
||||||
|
|
||||||
|
## 模块说明
|
||||||
|
|
||||||
|
| 模块 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `cmvr-iot-admin` | Web 启动模块,包含 REST Controller、启动类和运行配置 |
|
||||||
|
| `cmvr-iot-framework` | Web、安全、配置、通用框架能力 |
|
||||||
|
| `cmvr-iot-common` | 公共工具、通用响应、基础常量和通用能力 |
|
||||||
|
| `cmvr-iot-system` | 系统管理、用户、角色、菜单、字典等基础业务 |
|
||||||
|
| `cmvr-iot-quartz` | 定时任务模块 |
|
||||||
|
| `cmvr-iot-generator` | 代码生成模块 |
|
||||||
|
| `cmvr-iot-device` | 设备领域模型与设备相关能力 |
|
||||||
|
| `cmvr-iot-test` | 测试任务、编排、执行实例等业务 |
|
||||||
|
| `cmvr-iot-vi` | VI 相关业务 |
|
||||||
|
| `cmvr-iot-ti` | TI 相关业务 |
|
||||||
|
| `cmvr-iot-evaluation` | 评测相关业务 |
|
||||||
|
| `cmvr-iot-inspection` | 巡检机器人、地图、任务、告警等业务 |
|
||||||
|
| `cmvr-iot-aima` | AIMA 相关业务 |
|
||||||
|
| `cmvr-iot-tts` | TTS 语音合成相关业务 |
|
||||||
|
| `cmvr-iot-api` | API 聚合模块 |
|
||||||
|
| `cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib` | gRPC proto 与生成代码模块 |
|
||||||
|
| `cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client` | 边缘设备 gRPC 客户端、设备控制服务和请求 VO |
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```text
|
||||||
|
cmvr-iot
|
||||||
|
├── cmvr-iot-admin # Spring Boot 启动模块
|
||||||
|
├── cmvr-iot-common # 公共模块
|
||||||
|
├── cmvr-iot-framework # 框架模块
|
||||||
|
├── cmvr-iot-system # 系统管理模块
|
||||||
|
├── cmvr-iot-device # 设备模块
|
||||||
|
├── cmvr-iot-test # 测试业务模块
|
||||||
|
├── cmvr-iot-api
|
||||||
|
│ └── cmvr-iot-edge
|
||||||
|
│ ├── cmvr-iot-grpc-lib # proto 与 gRPC 生成代码
|
||||||
|
│ └── cmvr-iot-grpc-client # gRPC 客户端与边缘控制服务
|
||||||
|
├── sql # 增量 SQL
|
||||||
|
├── Dockerfile
|
||||||
|
├── Jenkinsfile
|
||||||
|
└── pom.xml # Maven 父工程
|
||||||
|
```
|
||||||
|
|
||||||
|
## 环境要求
|
||||||
|
|
||||||
|
- JDK 1.8
|
||||||
|
- Maven 3.6+
|
||||||
|
- MySQL 5.7+/8.x
|
||||||
|
- Redis
|
||||||
|
- 可访问的 gRPC 机器人/边缘终端服务
|
||||||
|
- 可选:MinIO、外部大模型/TTS/评测服务
|
||||||
|
|
||||||
|
注意:`application-*.yml` 中包含环境相关地址、账号和密钥配置。实际部署或本地开发时,应使用本机配置、环境变量或配置中心覆盖,不要直接复用生产/测试环境敏感配置。
|
||||||
|
|
||||||
|
## 配置文件
|
||||||
|
|
||||||
|
主配置文件位于:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cmvr-iot-admin/src/main/resources/application.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
环境配置文件位于:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cmvr-iot-admin/src/main/resources/application-dev.yml
|
||||||
|
cmvr-iot-admin/src/main/resources/application-test.yml
|
||||||
|
cmvr-iot-admin/src/main/resources/application-prod.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
当前 `application.yml` 默认激活:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
spring:
|
||||||
|
profiles:
|
||||||
|
active: test
|
||||||
|
```
|
||||||
|
|
||||||
|
如需切换环境,可以修改 `spring.profiles.active`,或启动时指定:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
java -jar cmvr-iot-admin-dev.jar --spring.profiles.active=dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建
|
||||||
|
|
||||||
|
在项目根目录执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn clean package -DskipTests
|
||||||
|
```
|
||||||
|
|
||||||
|
只编译启动模块及其依赖:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn -pl cmvr-iot-admin -am compile -DskipTests
|
||||||
|
```
|
||||||
|
|
||||||
|
只重新生成并编译 gRPC 代码:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn -pl cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib -am compile -DskipTests
|
||||||
|
```
|
||||||
|
|
||||||
|
## 启动
|
||||||
|
|
||||||
|
启动类:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cmvr-iot-admin/src/main/java/com/cmvr/CmvrIotApplication.java
|
||||||
|
```
|
||||||
|
|
||||||
|
IDE 中直接运行 `CmvrIotApplication` 即可。
|
||||||
|
|
||||||
|
打包后运行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
java -jar cmvr-iot-admin/target/cmvr-iot-admin-dev.jar --spring.profiles.active=dev
|
||||||
|
```
|
||||||
|
|
||||||
|
默认开发端口以当前 profile 配置为准,例如 `application-dev.yml` 中为:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
server:
|
||||||
|
port: 13080
|
||||||
|
```
|
||||||
|
|
||||||
|
## 接口文档
|
||||||
|
|
||||||
|
项目集成 Knife4j / Swagger。服务启动后可访问:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://localhost:13080/doc.html
|
||||||
|
```
|
||||||
|
|
||||||
|
如果端口或上下文路径被 profile 覆盖,请以实际配置为准。
|
||||||
|
|
||||||
|
## 数据库脚本
|
||||||
|
|
||||||
|
增量脚本位于:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sql/
|
||||||
|
```
|
||||||
|
|
||||||
|
当前包含:
|
||||||
|
|
||||||
|
- `aima_module.sql`
|
||||||
|
- `inspection_module.sql`
|
||||||
|
- `tts_corpus_module.sql`
|
||||||
|
|
||||||
|
初始化数据库时,需要结合目标环境的基础库结构和增量脚本执行。
|
||||||
|
|
||||||
|
## gRPC 与边缘设备
|
||||||
|
|
||||||
|
边缘设备相关代码集中在:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cmvr-iot-api/cmvr-iot-edge/
|
||||||
|
```
|
||||||
|
|
||||||
|
proto 文件位于:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/src/main/proto/
|
||||||
|
```
|
||||||
|
|
||||||
|
gRPC 客户端服务位于:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/
|
||||||
|
```
|
||||||
|
|
||||||
|
边缘控制器位于:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cmvr-iot-admin/src/main/java/com/cmvr/web/controller/api/
|
||||||
|
```
|
||||||
|
|
||||||
|
新增或修改 proto 后,执行 Maven compile 会触发 `protoc-maven-plugin` 生成 Java 和 gRPC Stub 代码。业务代码应复用现有 gRPC 客户端管理工具获取 Stub,避免在业务层重复创建底层 `ManagedChannel`。
|
||||||
|
|
||||||
|
## 实时语音对讲
|
||||||
|
|
||||||
|
当前实时语音对讲链路为:
|
||||||
|
|
||||||
|
```text
|
||||||
|
浏览器 WebSocket Binary PCM <-> Java 后端 <-> gRPC 双向流 <-> 机器人终端
|
||||||
|
```
|
||||||
|
|
||||||
|
约定音频格式:
|
||||||
|
|
||||||
|
- PCM_S16LE
|
||||||
|
- 48000 Hz
|
||||||
|
- 单声道
|
||||||
|
- 16 bit
|
||||||
|
- 10 ms 一帧
|
||||||
|
- 960 bytes/帧
|
||||||
|
|
||||||
|
相关文件:
|
||||||
|
|
||||||
|
- WebSocket 控制器:`cmvr-iot-admin/src/main/java/com/cmvr/web/controller/api/WebRtcSignalingController.java`
|
||||||
|
- 业务会话管理:`cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/AudioService.java`
|
||||||
|
- gRPC 音频适配:`cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/adapter/RobotAudioGrpcAdapter.java`
|
||||||
|
- proto:`cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/src/main/proto/cmvr/api/robot_audio.proto`
|
||||||
|
|
||||||
|
说明:历史 WebRTC 相关类可能仍保留在源码中,但当前浏览器音频传输链路使用 WebSocket 二进制 PCM。
|
||||||
|
|
||||||
|
## 开发约定
|
||||||
|
|
||||||
|
- Controller 层只做参数接收、基础校验和响应封装。
|
||||||
|
- POST 控制类接口优先使用单个 `@RequestBody VO` 承载完整请求参数。
|
||||||
|
- GET 查询类接口可以使用 query 参数绑定 VO。
|
||||||
|
- 不建议在同一个接口中同时声明通用 VO 和零散业务参数。
|
||||||
|
- gRPC 调用统一通过现有客户端管理类获取 Stub。
|
||||||
|
- proto 修改后必须重新编译并确认生成代码已更新。
|
||||||
|
- 不要提交本地日志、崩溃 dump、临时音频文件和包含真实密钥的配置。
|
||||||
|
|
||||||
|
## 常用命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 编译全部模块
|
||||||
|
mvn clean compile -DskipTests
|
||||||
|
|
||||||
|
# 编译启动模块及依赖
|
||||||
|
mvn -pl cmvr-iot-admin -am compile -DskipTests
|
||||||
|
|
||||||
|
# 打包
|
||||||
|
mvn clean package -DskipTests
|
||||||
|
|
||||||
|
# 运行指定 profile
|
||||||
|
java -jar cmvr-iot-admin/target/cmvr-iot-admin-dev.jar --spring.profiles.active=dev
|
||||||
|
```
|
||||||
@ -77,6 +77,24 @@
|
|||||||
<groupId>com.cmvr</groupId>
|
<groupId>com.cmvr</groupId>
|
||||||
<artifactId>cmvr-iot-evaluation</artifactId>
|
<artifactId>cmvr-iot-evaluation</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 智能巡检-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot-inspection</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 爱玛电动车测试-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot-aima</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 智能座舱语音语料采集-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot-tts</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<properties>
|
<properties>
|
||||||
<env>dev</env>
|
<env>dev</env>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.cmvr;
|
package com.cmvr;
|
||||||
|
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
@ -11,6 +12,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
|||||||
* @author cmvr-iot
|
* @author cmvr-iot
|
||||||
*/
|
*/
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
|
@MapperScan("com.cmvr.**.mapper")
|
||||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
||||||
public class CmvrIotApplication
|
public class CmvrIotApplication
|
||||||
{
|
{
|
||||||
|
|||||||
@ -0,0 +1,75 @@
|
|||||||
|
package com.cmvr.web.controller.aima;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.aima.domain.AimaAlarm;
|
||||||
|
import com.cmvr.aima.service.IAimaAlarmService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/aima/alarm")
|
||||||
|
@Api(tags = "爱玛电动车--告警管理")
|
||||||
|
public class AimaAlarmController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IAimaAlarmService aimaAlarmService;
|
||||||
|
|
||||||
|
@ApiOperation("查询告警列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:alarm:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(AimaAlarm aimaAlarm) {
|
||||||
|
startPage();
|
||||||
|
List<AimaAlarm> list = aimaAlarmService.selectAimaAlarmList(aimaAlarm);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("导出告警列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:alarm:export')")
|
||||||
|
@Log(title = "告警管理", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, AimaAlarm aimaAlarm) {
|
||||||
|
List<AimaAlarm> list = aimaAlarmService.selectAimaAlarmList(aimaAlarm);
|
||||||
|
ExcelUtil<AimaAlarm> util = new ExcelUtil<>(AimaAlarm.class);
|
||||||
|
util.exportExcel(response, list, "告警数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取告警详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:alarm:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||||
|
return success(aimaAlarmService.selectAimaAlarmById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("新增告警")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:alarm:add')")
|
||||||
|
@Log(title = "告警管理", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody AimaAlarm aimaAlarm) {
|
||||||
|
return toAjax(aimaAlarmService.insertAimaAlarm(aimaAlarm));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("修改告警")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:alarm:edit')")
|
||||||
|
@Log(title = "告警管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody AimaAlarm aimaAlarm) {
|
||||||
|
return toAjax(aimaAlarmService.updateAimaAlarm(aimaAlarm));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除告警")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:alarm:remove')")
|
||||||
|
@Log(title = "告警管理", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids) {
|
||||||
|
return toAjax(aimaAlarmService.deleteAimaAlarmByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
package com.cmvr.web.controller.aima;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.aima.domain.AimaPhone;
|
||||||
|
import com.cmvr.aima.service.IAimaPhoneService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛手机管理Controller
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/aima/phone")
|
||||||
|
@Api(tags = "爱玛电动车--手机管理")
|
||||||
|
public class AimaPhoneController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IAimaPhoneService aimaPhoneService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛手机管理列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询爱玛手机管理列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:phone:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(AimaPhone aimaPhone)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<AimaPhone> list = aimaPhoneService.selectAimaPhoneList(aimaPhone);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出爱玛手机管理列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("导出爱玛手机管理列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:phone:export')")
|
||||||
|
@Log(title = "爱玛手机管理", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, AimaPhone aimaPhone)
|
||||||
|
{
|
||||||
|
List<AimaPhone> list = aimaPhoneService.selectAimaPhoneList(aimaPhone);
|
||||||
|
ExcelUtil<AimaPhone> util = new ExcelUtil<>(AimaPhone.class);
|
||||||
|
util.exportExcel(response, list, "爱玛手机管理数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取爱玛手机管理详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取爱玛手机管理详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:phone:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||||
|
{
|
||||||
|
return success(aimaPhoneService.selectAimaPhoneById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛手机管理
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增爱玛手机管理")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:phone:add')")
|
||||||
|
@Log(title = "爱玛手机管理", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody AimaPhone aimaPhone)
|
||||||
|
{
|
||||||
|
return toAjax(aimaPhoneService.insertAimaPhone(aimaPhone));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛手机管理
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改爱玛手机管理")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:phone:edit')")
|
||||||
|
@Log(title = "爱玛手机管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody AimaPhone aimaPhone)
|
||||||
|
{
|
||||||
|
return toAjax(aimaPhoneService.updateAimaPhone(aimaPhone));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛手机管理
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除爱玛手机管理")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:phone:remove')")
|
||||||
|
@Log(title = "爱玛手机管理", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(aimaPhoneService.deleteAimaPhoneByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,98 @@
|
|||||||
|
package com.cmvr.web.controller.aima;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.aima.domain.AimaTask;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTaskVo;
|
||||||
|
import com.cmvr.aima.service.IAimaTaskService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/aima/task")
|
||||||
|
@Api(tags = "爱玛电动车--任务管理")
|
||||||
|
public class AimaTaskController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IAimaTaskService aimaTaskService;
|
||||||
|
|
||||||
|
@ApiOperation("查询任务列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:task:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(AimaTask aimaTask) {
|
||||||
|
startPage();
|
||||||
|
List<AimaTaskVo> list = aimaTaskService.selectAimaTaskVoList(aimaTask);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("导出任务列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:task:export')")
|
||||||
|
@Log(title = "任务管理", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, AimaTask aimaTask) {
|
||||||
|
List<AimaTaskVo> list = aimaTaskService.selectAimaTaskVoList(aimaTask);
|
||||||
|
ExcelUtil<AimaTaskVo> util = new ExcelUtil<>(AimaTaskVo.class);
|
||||||
|
util.exportExcel(response, list, "任务数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取任务详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:task:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||||
|
return success(aimaTaskService.selectAimaTaskById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("新增任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:task:add')")
|
||||||
|
@Log(title = "任务管理", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody AimaTask aimaTask) {
|
||||||
|
return toAjax(aimaTaskService.insertAimaTask(aimaTask));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("修改任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:task:edit')")
|
||||||
|
@Log(title = "任务管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody AimaTask aimaTask) {
|
||||||
|
return toAjax(aimaTaskService.updateAimaTask(aimaTask));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:task:remove')")
|
||||||
|
@Log(title = "任务管理", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids) {
|
||||||
|
return toAjax(aimaTaskService.deleteAimaTaskByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定测试用例到任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("绑定测试用例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:task:edit')")
|
||||||
|
@Log(title = "任务管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/bindTestCases/{taskId}")
|
||||||
|
public AjaxResult bindTestCases(@PathVariable("taskId") String taskId, @RequestBody List<String> testCaseIds) {
|
||||||
|
aimaTaskService.bindTestCases(taskId, testCaseIds);
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取任务的测试用例列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取任务测试用例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:task:query')")
|
||||||
|
@GetMapping("/testCases/{taskId}")
|
||||||
|
public AjaxResult getTestCases(@PathVariable String taskId) {
|
||||||
|
return success(aimaTaskService.getTestCaseIds(taskId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,121 @@
|
|||||||
|
package com.cmvr.web.controller.aima;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.aima.domain.AimaTaskInstance;
|
||||||
|
import com.cmvr.aima.domain.dto.AimaTaskInstanceQuery;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTaskInstanceVo;
|
||||||
|
import com.cmvr.aima.service.IAimaTaskInstanceService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/aima/taskinstance")
|
||||||
|
@Api(tags = "爱玛电动车--任务执行实例")
|
||||||
|
public class AimaTaskInstanceController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IAimaTaskInstanceService aimaTaskInstanceService;
|
||||||
|
|
||||||
|
@ApiOperation("查询任务实例列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:taskinstance:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(AimaTaskInstanceQuery query) {
|
||||||
|
startPage();
|
||||||
|
List<AimaTaskInstanceVo> list = aimaTaskInstanceService.selectAimaTaskInstanceVoList(query);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("导出任务实例列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:taskinstance:export')")
|
||||||
|
@Log(title = "任务执行实例", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, AimaTaskInstanceQuery query) {
|
||||||
|
List<AimaTaskInstanceVo> list = aimaTaskInstanceService.selectAimaTaskInstanceVoList(query);
|
||||||
|
ExcelUtil<AimaTaskInstanceVo> util = new ExcelUtil<>(AimaTaskInstanceVo.class);
|
||||||
|
util.exportExcel(response, list, "任务实例数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取任务实例详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:taskinstance:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||||
|
return success(aimaTaskInstanceService.selectAimaTaskInstanceById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("新增任务实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:taskinstance:add')")
|
||||||
|
@Log(title = "任务执行实例", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody AimaTaskInstance aimaTaskInstance) {
|
||||||
|
return toAjax(aimaTaskInstanceService.insertAimaTaskInstance(aimaTaskInstance));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("修改任务实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:taskinstance:edit')")
|
||||||
|
@Log(title = "任务执行实例", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody AimaTaskInstance aimaTaskInstance) {
|
||||||
|
return toAjax(aimaTaskInstanceService.updateAimaTaskInstance(aimaTaskInstance));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除任务实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:taskinstance:remove')")
|
||||||
|
@Log(title = "任务执行实例", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids) {
|
||||||
|
return toAjax(aimaTaskInstanceService.deleteAimaTaskInstanceByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始执行任务实例
|
||||||
|
*/
|
||||||
|
@ApiOperation("开始执行任务实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:taskinstance:edit')")
|
||||||
|
@Log(title = "任务执行实例", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/start/{id}")
|
||||||
|
public AjaxResult start(@PathVariable("id") String id) {
|
||||||
|
return toAjax(aimaTaskInstanceService.startInstance(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停任务实例
|
||||||
|
*/
|
||||||
|
@ApiOperation("暂停任务实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:taskinstance:edit')")
|
||||||
|
@Log(title = "任务执行实例", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/pause/{id}")
|
||||||
|
public AjaxResult pause(@PathVariable("id") String id) {
|
||||||
|
return toAjax(aimaTaskInstanceService.pauseInstance(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终止任务实例
|
||||||
|
*/
|
||||||
|
@ApiOperation("终止任务实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:taskinstance:edit')")
|
||||||
|
@Log(title = "任务执行实例", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/stop/{id}")
|
||||||
|
public AjaxResult stop(@PathVariable("id") String id) {
|
||||||
|
return toAjax(aimaTaskInstanceService.stopInstance(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复任务实例
|
||||||
|
*/
|
||||||
|
@ApiOperation("恢复任务实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:taskinstance:edit')")
|
||||||
|
@Log(title = "任务执行实例", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/resume/{id}")
|
||||||
|
public AjaxResult resume(@PathVariable("id") String id) {
|
||||||
|
return toAjax(aimaTaskInstanceService.resumeInstance(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
package com.cmvr.web.controller.aima;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.aima.domain.AimaTestCase;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTestCaseVo;
|
||||||
|
import com.cmvr.aima.service.IAimaTestCaseService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/aima/testcase")
|
||||||
|
@Api(tags = "爱玛电动车--测试用例管理")
|
||||||
|
public class AimaTestCaseController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IAimaTestCaseService aimaTestCaseService;
|
||||||
|
|
||||||
|
@ApiOperation("查询测试用例列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testcase:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(AimaTestCase aimaTestCase) {
|
||||||
|
startPage();
|
||||||
|
List<AimaTestCaseVo> list = aimaTestCaseService.selectAimaTestCaseVoList(aimaTestCase);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("导出测试用例列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testcase:export')")
|
||||||
|
@Log(title = "测试用例管理", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, AimaTestCase aimaTestCase) {
|
||||||
|
List<AimaTestCaseVo> list = aimaTestCaseService.selectAimaTestCaseVoList(aimaTestCase);
|
||||||
|
ExcelUtil<AimaTestCaseVo> util = new ExcelUtil<>(AimaTestCaseVo.class);
|
||||||
|
util.exportExcel(response, list, "测试用例数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取测试用例详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testcase:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||||
|
return success(aimaTestCaseService.selectAimaTestCaseById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("新增测试用例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testcase:add')")
|
||||||
|
@Log(title = "测试用例管理", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody AimaTestCase aimaTestCase) {
|
||||||
|
return toAjax(aimaTestCaseService.insertAimaTestCase(aimaTestCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("修改测试用例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testcase:edit')")
|
||||||
|
@Log(title = "测试用例管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody AimaTestCase aimaTestCase) {
|
||||||
|
return toAjax(aimaTestCaseService.updateAimaTestCase(aimaTestCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除测试用例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testcase:remove')")
|
||||||
|
@Log(title = "测试用例管理", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids) {
|
||||||
|
return toAjax(aimaTestCaseService.deleteAimaTestCaseByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
package com.cmvr.web.controller.aima;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.aima.domain.AimaTestLog;
|
||||||
|
import com.cmvr.aima.service.IAimaTestLogService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/aima/testlog")
|
||||||
|
@Api(tags = "爱玛电动车--测试日志管理")
|
||||||
|
public class AimaTestLogController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IAimaTestLogService aimaTestLogService;
|
||||||
|
|
||||||
|
@ApiOperation("查询测试日志列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testlog:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(AimaTestLog aimaTestLog) {
|
||||||
|
startPage();
|
||||||
|
List<AimaTestLog> list = aimaTestLogService.selectAimaTestLogList(aimaTestLog);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("导出测试日志列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testlog:export')")
|
||||||
|
@Log(title = "测试日志管理", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, AimaTestLog aimaTestLog) {
|
||||||
|
List<AimaTestLog> list = aimaTestLogService.selectAimaTestLogList(aimaTestLog);
|
||||||
|
ExcelUtil<AimaTestLog> util = new ExcelUtil<>(AimaTestLog.class);
|
||||||
|
util.exportExcel(response, list, "测试日志数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取测试日志详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testlog:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||||
|
return success(aimaTestLogService.selectAimaTestLogById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("新增测试日志")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testlog:add')")
|
||||||
|
@Log(title = "测试日志管理", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody AimaTestLog aimaTestLog) {
|
||||||
|
return toAjax(aimaTestLogService.insertAimaTestLog(aimaTestLog));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("修改测试日志")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testlog:edit')")
|
||||||
|
@Log(title = "测试日志管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody AimaTestLog aimaTestLog) {
|
||||||
|
return toAjax(aimaTestLogService.updateAimaTestLog(aimaTestLog));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除测试日志")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:testlog:remove')")
|
||||||
|
@Log(title = "测试日志管理", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids) {
|
||||||
|
return toAjax(aimaTestLogService.deleteAimaTestLogByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
package com.cmvr.web.controller.aima;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.aima.domain.AimaVehicle;
|
||||||
|
import com.cmvr.aima.service.IAimaVehicleService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/aima/vehicle")
|
||||||
|
@Api(tags = "爱玛电动车--车辆管理")
|
||||||
|
public class AimaVehicleController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IAimaVehicleService aimaVehicleService;
|
||||||
|
|
||||||
|
@ApiOperation("查询车辆列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:vehicle:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(AimaVehicle aimaVehicle) {
|
||||||
|
startPage();
|
||||||
|
List<AimaVehicle> list = aimaVehicleService.selectAimaVehicleList(aimaVehicle);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("导出车辆列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:vehicle:export')")
|
||||||
|
@Log(title = "车辆管理", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, AimaVehicle aimaVehicle) {
|
||||||
|
List<AimaVehicle> list = aimaVehicleService.selectAimaVehicleList(aimaVehicle);
|
||||||
|
ExcelUtil<AimaVehicle> util = new ExcelUtil<>(AimaVehicle.class);
|
||||||
|
util.exportExcel(response, list, "车辆数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取车辆详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:vehicle:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||||
|
return success(aimaVehicleService.selectAimaVehicleById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("新增车辆")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:vehicle:add')")
|
||||||
|
@Log(title = "车辆管理", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody AimaVehicle aimaVehicle) {
|
||||||
|
return toAjax(aimaVehicleService.insertAimaVehicle(aimaVehicle));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("修改车辆")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:vehicle:edit')")
|
||||||
|
@Log(title = "车辆管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody AimaVehicle aimaVehicle) {
|
||||||
|
return toAjax(aimaVehicleService.updateAimaVehicle(aimaVehicle));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除车辆")
|
||||||
|
@PreAuthorize("@ss.hasPermi('aima:vehicle:remove')")
|
||||||
|
@Log(title = "车辆管理", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids) {
|
||||||
|
return toAjax(aimaVehicleService.deleteAimaVehicleByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,315 @@
|
|||||||
|
package com.cmvr.web.controller.api;
|
||||||
|
|
||||||
|
import cmvr.msgs.Agv;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
|
import com.cmvr.edge.client.model.agv.EdgeAgvMapNameVO;
|
||||||
|
import com.cmvr.edge.client.model.agv.EdgeAgvNavigateToPoseVO;
|
||||||
|
import com.cmvr.edge.client.model.agv.EdgeAgvNavigateToStationVO;
|
||||||
|
import com.cmvr.edge.client.model.agv.EdgeAgvStartMappingVO;
|
||||||
|
import com.cmvr.edge.client.model.agv.EdgeAgvUploadMapVO;
|
||||||
|
import com.cmvr.edge.client.model.agv.EdgeAgvVelocityVO;
|
||||||
|
import com.cmvr.edge.client.service.EdgeAgvService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 边缘系统 AGV 控制器。
|
||||||
|
*
|
||||||
|
* <p>接口入参约定:
|
||||||
|
* GET 查询类接口使用 query 参数绑定 VO;POST 控制类接口只接收一个 JSON 请求体 VO,
|
||||||
|
* 避免一个接口同时出现通用 VO 和零散业务参数,保证前端调用、Swagger 文档和后端绑定规则一致。</p>
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-07-02
|
||||||
|
*/
|
||||||
|
@Api(tags = "边缘--AGV")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/agv")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class EdgeAgvController {
|
||||||
|
|
||||||
|
private final EdgeAgvService edgeAgvService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 AGV 运行时状态。
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取AGV运行时状态")
|
||||||
|
@GetMapping("/getRuntimeState")
|
||||||
|
public AjaxResult getRuntimeState(@Validated EdgeCommonVO vo) {
|
||||||
|
Agv.AgvRuntimeState state = edgeAgvService.getRuntimeState(vo);
|
||||||
|
return AjaxResult.ok(toRuntimeStateMap(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 AGV 当前导航状态。
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取导航状态")
|
||||||
|
@GetMapping("/getNavigationStatus")
|
||||||
|
public AjaxResult getNavigationStatus(@Validated EdgeCommonVO vo) {
|
||||||
|
Agv.AgvNavigationStatus status = edgeAgvService.getNavigationStatus(vo);
|
||||||
|
Map<String, Object> resultMap = new HashMap<>();
|
||||||
|
resultMap.put("state", status.getState());
|
||||||
|
resultMap.put("type", status.getType());
|
||||||
|
resultMap.put("progress", status.getProgress());
|
||||||
|
resultMap.put("message", status.getMessage());
|
||||||
|
return AjaxResult.ok(resultMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV 紧急停止。
|
||||||
|
*/
|
||||||
|
@ApiOperation("紧急停止")
|
||||||
|
@PostMapping("/emergencyStop")
|
||||||
|
public AjaxResult emergencyStop(@RequestBody @Validated EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.emergencyStop(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除 AGV 故障。
|
||||||
|
*/
|
||||||
|
@ApiOperation("清除故障")
|
||||||
|
@PostMapping("/clearFault")
|
||||||
|
public AjaxResult clearFault(@RequestBody @Validated EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.clearFault(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航到指定坐标。
|
||||||
|
*/
|
||||||
|
@ApiOperation("导航到指定位置")
|
||||||
|
@PostMapping("/navigateToPose")
|
||||||
|
public AjaxResult navigateToPose(@RequestBody @Validated EdgeAgvNavigateToPoseVO vo) {
|
||||||
|
Agv.AgvPose2d pose = Agv.AgvPose2d.newBuilder()
|
||||||
|
.setX(vo.getX())
|
||||||
|
.setY(vo.getY())
|
||||||
|
.setTheta(vo.getTheta())
|
||||||
|
.build();
|
||||||
|
edgeAgvService.navigateToPose(vo, pose);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航到指定站点。
|
||||||
|
*/
|
||||||
|
@ApiOperation("导航到站点")
|
||||||
|
@PostMapping("/navigateToStation")
|
||||||
|
public AjaxResult navigateToStation(@RequestBody @Validated EdgeAgvNavigateToStationVO vo) {
|
||||||
|
edgeAgvService.navigateToStation(vo, vo.getStationId());
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停当前导航任务。
|
||||||
|
*/
|
||||||
|
@ApiOperation("暂停导航")
|
||||||
|
@PostMapping("/pauseNavigation")
|
||||||
|
public AjaxResult pauseNavigation(@RequestBody @Validated EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.pauseNavigation(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复当前导航任务。
|
||||||
|
*/
|
||||||
|
@ApiOperation("恢复导航")
|
||||||
|
@PostMapping("/resumeNavigation")
|
||||||
|
public AjaxResult resumeNavigation(@RequestBody @Validated EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.resumeNavigation(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消当前导航任务。
|
||||||
|
*/
|
||||||
|
@ApiOperation("取消导航")
|
||||||
|
@PostMapping("/cancelNavigation")
|
||||||
|
public AjaxResult cancelNavigation(@RequestBody @Validated EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.cancelNavigation(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 AGV 速度。
|
||||||
|
*/
|
||||||
|
@ApiOperation("设置速度")
|
||||||
|
@PostMapping("/setVelocity")
|
||||||
|
public AjaxResult setVelocity(@RequestBody @Validated EdgeAgvVelocityVO vo) {
|
||||||
|
Agv.AgvVelocity velocity = Agv.AgvVelocity.newBuilder()
|
||||||
|
.setVx(vo.getVx())
|
||||||
|
.setVy(vo.getVy())
|
||||||
|
.setWz(vo.getWz())
|
||||||
|
.build();
|
||||||
|
edgeAgvService.setVelocity(vo, velocity);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止速度控制。
|
||||||
|
*/
|
||||||
|
@ApiOperation("停止速度控制")
|
||||||
|
@PostMapping("/stopVelocityControl")
|
||||||
|
public AjaxResult stopVelocityControl(@RequestBody @Validated EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.stopVelocityControl(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询机器人本地所有地图。
|
||||||
|
*/
|
||||||
|
@ApiOperation("列出所有地图")
|
||||||
|
@GetMapping("/listMaps")
|
||||||
|
public AjaxResult listMaps(@Validated EdgeCommonVO vo) {
|
||||||
|
List<String> maps = edgeAgvService.listMaps(vo);
|
||||||
|
return AjaxResult.ok(maps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询机器人本地所有站点。
|
||||||
|
*/
|
||||||
|
@ApiOperation("列出所有站点")
|
||||||
|
@GetMapping("/listStations")
|
||||||
|
public AjaxResult listStations(@Validated EdgeCommonVO vo) {
|
||||||
|
List<Agv.AgvStation> stations = edgeAgvService.listStations(vo);
|
||||||
|
List<Map<String, Object>> stationList = new ArrayList<>();
|
||||||
|
for (Agv.AgvStation station : stations) {
|
||||||
|
stationList.add(toStationMap(station));
|
||||||
|
}
|
||||||
|
return AjaxResult.ok(stationList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换机器人当前地图。
|
||||||
|
*/
|
||||||
|
@ApiOperation("切换地图")
|
||||||
|
@PostMapping("/switchMap")
|
||||||
|
public AjaxResult switchMap(@RequestBody @Validated EdgeAgvMapNameVO vo) {
|
||||||
|
edgeAgvService.switchMap(vo, vo.getMapName());
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传地图内容到机器人。
|
||||||
|
*/
|
||||||
|
@ApiOperation("上传地图")
|
||||||
|
@PostMapping("/uploadMap")
|
||||||
|
public AjaxResult uploadMap(@RequestBody @Validated EdgeAgvUploadMapVO vo) {
|
||||||
|
edgeAgvService.uploadMap(vo, vo.getMapName(), vo.getContent());
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载指定地图内容。
|
||||||
|
*/
|
||||||
|
@ApiOperation("下载地图")
|
||||||
|
@GetMapping("/downloadMap")
|
||||||
|
public AjaxResult downloadMap(@Validated EdgeAgvMapNameVO vo) {
|
||||||
|
String content = edgeAgvService.downloadMap(vo, vo.getMapName());
|
||||||
|
return AjaxResult.ok(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始建图。
|
||||||
|
*/
|
||||||
|
@ApiOperation("开始建图")
|
||||||
|
@PostMapping("/startMapping")
|
||||||
|
public AjaxResult startMapping(@RequestBody @Validated EdgeAgvStartMappingVO vo) {
|
||||||
|
Agv.AgvMapDimension mapDimension = Agv.AgvMapDimension.forNumber(vo.getDimension());
|
||||||
|
if (mapDimension == null) {
|
||||||
|
return AjaxResult.error("建图维度不合法,允许值:0=未指定,1=2D,2=3D,3=2D+3D");
|
||||||
|
}
|
||||||
|
|
||||||
|
String sessionId = edgeAgvService.startMapping(vo, mapDimension, vo.getMapName(), vo.isRealTime());
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("sessionId", sessionId);
|
||||||
|
return AjaxResult.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止建图。
|
||||||
|
*/
|
||||||
|
@ApiOperation("停止建图")
|
||||||
|
@PostMapping("/stopMapping")
|
||||||
|
public AjaxResult stopMapping(@RequestBody @Validated EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.stopMapping(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 protobuf 运行时状态转换为前端友好的 Map,避免直接暴露 protobuf 对象结构。
|
||||||
|
*/
|
||||||
|
private Map<String, Object> toRuntimeStateMap(Agv.AgvRuntimeState state) {
|
||||||
|
Map<String, Object> resultMap = new HashMap<>();
|
||||||
|
resultMap.put("timestamp", state.getTimestamp());
|
||||||
|
resultMap.put("mode", state.getMode());
|
||||||
|
resultMap.put("connected", state.getConnected());
|
||||||
|
resultMap.put("localized", state.getLocalized());
|
||||||
|
resultMap.put("moving", state.getMoving());
|
||||||
|
resultMap.put("fault", state.getFault());
|
||||||
|
resultMap.put("emergencyStopped", state.getEmergencyStopped());
|
||||||
|
|
||||||
|
if (state.hasPose()) {
|
||||||
|
resultMap.put("pose", toPoseMap(state.getPose()));
|
||||||
|
}
|
||||||
|
if (state.hasVelocity()) {
|
||||||
|
Map<String, Object> velocityMap = new HashMap<>();
|
||||||
|
velocityMap.put("vx", state.getVelocity().getVx());
|
||||||
|
velocityMap.put("vy", state.getVelocity().getVy());
|
||||||
|
velocityMap.put("wz", state.getVelocity().getWz());
|
||||||
|
resultMap.put("velocity", velocityMap);
|
||||||
|
}
|
||||||
|
if (state.hasBattery()) {
|
||||||
|
Map<String, Object> batteryMap = new HashMap<>();
|
||||||
|
batteryMap.put("percentage", state.getBattery().getPercentage());
|
||||||
|
batteryMap.put("voltage", state.getBattery().getVoltage());
|
||||||
|
batteryMap.put("current", state.getBattery().getCurrent());
|
||||||
|
batteryMap.put("temperature", state.getBattery().getTemperature());
|
||||||
|
batteryMap.put("charging", state.getBattery().getCharging());
|
||||||
|
resultMap.put("battery", batteryMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
resultMap.put("currentMap", state.getCurrentMap());
|
||||||
|
resultMap.put("currentStation", state.getCurrentStation());
|
||||||
|
resultMap.put("lastError", state.getLastError());
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 protobuf 站点对象转换为普通 Map。
|
||||||
|
*/
|
||||||
|
private Map<String, Object> toStationMap(Agv.AgvStation station) {
|
||||||
|
Map<String, Object> stationMap = new HashMap<>();
|
||||||
|
stationMap.put("id", station.getId());
|
||||||
|
stationMap.put("type", station.getType());
|
||||||
|
stationMap.put("description", station.getDescription());
|
||||||
|
if (station.hasPose()) {
|
||||||
|
stationMap.put("pose", toPoseMap(station.getPose()));
|
||||||
|
}
|
||||||
|
return stationMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 protobuf 二维位姿转换为普通 Map。
|
||||||
|
*/
|
||||||
|
private Map<String, Object> toPoseMap(Agv.AgvPose2d pose) {
|
||||||
|
Map<String, Object> poseMap = new HashMap<>();
|
||||||
|
poseMap.put("x", pose.getX());
|
||||||
|
poseMap.put("y", pose.getY());
|
||||||
|
poseMap.put("theta", pose.getTheta());
|
||||||
|
return poseMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,232 @@
|
|||||||
|
package com.cmvr.web.controller.api;
|
||||||
|
|
||||||
|
import cmvr.api.ArmCommand;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
|
import com.cmvr.edge.client.model.arm.*;
|
||||||
|
import com.cmvr.edge.client.service.EdgeArmService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 边缘系统机械臂控制器
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-07-01
|
||||||
|
*/
|
||||||
|
@Api(tags = "边缘--机械臂")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/arm")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class EdgeArmController {
|
||||||
|
|
||||||
|
private final EdgeArmService edgeArmService;
|
||||||
|
|
||||||
|
@ApiOperation("关闭力矩")
|
||||||
|
@GetMapping("/torqueOff")
|
||||||
|
public AjaxResult torqueOff(EdgeCommonVO vo) {
|
||||||
|
edgeArmService.torqueOff(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("开启力矩")
|
||||||
|
@GetMapping("/torqueOn")
|
||||||
|
public AjaxResult torqueOn(EdgeCommonVO vo) {
|
||||||
|
edgeArmService.torqueOn(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除机械臂故障状态。
|
||||||
|
*/
|
||||||
|
@ApiOperation("清除故障")
|
||||||
|
@GetMapping("/clearFault")
|
||||||
|
public AjaxResult clearFault(EdgeCommonVO vo) {
|
||||||
|
edgeArmService.clearFault(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("关节空间运动")
|
||||||
|
@PostMapping("/moveJ")
|
||||||
|
public AjaxResult moveJ(@RequestBody EdgeArmMoveJVO moveJVO) {
|
||||||
|
edgeArmService.moveJ(
|
||||||
|
moveJVO,
|
||||||
|
moveJVO.getTarget(),
|
||||||
|
moveJVO.getVelocity(),
|
||||||
|
moveJVO.getAcceleration(),
|
||||||
|
moveJVO.getBlendRadius(),
|
||||||
|
moveJVO.getJointVelocityLimits(),
|
||||||
|
moveJVO.getAsynchronous()
|
||||||
|
);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("笛卡尔空间直线运动")
|
||||||
|
@PostMapping("/moveL")
|
||||||
|
public AjaxResult moveL(@RequestBody EdgeArmMoveLVO moveLVO) {
|
||||||
|
edgeArmService.moveL(
|
||||||
|
moveLVO,
|
||||||
|
moveLVO.getX(),
|
||||||
|
moveLVO.getY(),
|
||||||
|
moveLVO.getZ(),
|
||||||
|
moveLVO.getRx(),
|
||||||
|
moveLVO.getRy(),
|
||||||
|
moveLVO.getRz(),
|
||||||
|
moveLVO.getFrame(),
|
||||||
|
moveLVO.getVelocity(),
|
||||||
|
moveLVO.getAcceleration(),
|
||||||
|
moveLVO.getBlendRadius()
|
||||||
|
);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("关节速度控制")
|
||||||
|
@PostMapping("/speedJ")
|
||||||
|
public AjaxResult speedJ(@RequestBody EdgeArmSpeedJVO speedJVO) {
|
||||||
|
edgeArmService.speedJ(
|
||||||
|
speedJVO,
|
||||||
|
speedJVO.getVelocities(),
|
||||||
|
speedJVO.getAcceleration(),
|
||||||
|
speedJVO.getDuration()
|
||||||
|
);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("笛卡尔速度控制")
|
||||||
|
@PostMapping("/speedL")
|
||||||
|
public AjaxResult speedL(@RequestBody EdgeArmSpeedLVO speedLVO) {
|
||||||
|
edgeArmService.speedL(
|
||||||
|
speedLVO,
|
||||||
|
speedLVO.getVx(),
|
||||||
|
speedLVO.getVy(),
|
||||||
|
speedLVO.getVz(),
|
||||||
|
speedLVO.getWx(),
|
||||||
|
speedLVO.getWy(),
|
||||||
|
speedLVO.getWz(),
|
||||||
|
speedLVO.getFrame(),
|
||||||
|
speedLVO.getAcceleration(),
|
||||||
|
speedLVO.getDuration()
|
||||||
|
);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("伺服关节控制")
|
||||||
|
@PostMapping("/servoJ")
|
||||||
|
public AjaxResult servoJ(@RequestBody EdgeArmServoJVO servoJVO) {
|
||||||
|
edgeArmService.servoJ(servoJVO, servoJVO.getTarget());
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("停止运动")
|
||||||
|
@GetMapping("/stopMotion")
|
||||||
|
public AjaxResult stopMotion(EdgeCommonVO vo) {
|
||||||
|
edgeArmService.stopMotion(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取关节状态")
|
||||||
|
@GetMapping("/getJointState")
|
||||||
|
public AjaxResult getJointState(EdgeCommonVO vo) {
|
||||||
|
ArmCommand.JointResponse result = edgeArmService.getJointState(vo);
|
||||||
|
ArmCommand.JointState state = result.getState();
|
||||||
|
|
||||||
|
// 转换为VO
|
||||||
|
EdgeArmJointStateVO jointStateVO = new EdgeArmJointStateVO();
|
||||||
|
jointStateVO.setName(state.getNameList());
|
||||||
|
jointStateVO.setPosition(state.getPositionList());
|
||||||
|
jointStateVO.setVelocity(state.getVelocityList());
|
||||||
|
jointStateVO.setEffort(state.getEffortList());
|
||||||
|
jointStateVO.setTimestamp(state.getTimestamp());
|
||||||
|
|
||||||
|
return AjaxResult.ok(jointStateVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取末端位姿")
|
||||||
|
@GetMapping("/getPose")
|
||||||
|
public AjaxResult getPose(@Validated EdgeArmPoseQueryVO vo) {
|
||||||
|
ArmCommand.GetPose.Response result = edgeArmService.getPose(vo, vo.getBaseLink(), vo.getEeLink());
|
||||||
|
ArmCommand.CartesianPose pose = result.getPose();
|
||||||
|
|
||||||
|
// 转换为VO
|
||||||
|
EdgeArmCartesianPoseVO poseVO = new EdgeArmCartesianPoseVO();
|
||||||
|
poseVO.setX(pose.getX());
|
||||||
|
poseVO.setY(pose.getY());
|
||||||
|
poseVO.setZ(pose.getZ());
|
||||||
|
poseVO.setRx(pose.getRx());
|
||||||
|
poseVO.setRy(pose.getRy());
|
||||||
|
poseVO.setRz(pose.getRz());
|
||||||
|
|
||||||
|
return AjaxResult.ok(poseVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("标定零点")
|
||||||
|
@GetMapping("/calibrateZeroQ")
|
||||||
|
public AjaxResult calibrateZeroQ(@Validated EdgeArmCalibrateZeroQVO vo) {
|
||||||
|
edgeArmService.calibrateZeroQ(vo, vo.getJointName());
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取位姿矩阵")
|
||||||
|
@GetMapping("/getPoseMatrix")
|
||||||
|
public AjaxResult getPoseMatrix(@Validated EdgeArmPoseQueryVO vo) {
|
||||||
|
ArmCommand.GetPoseMatrix.Response result = edgeArmService.getPoseMatrix(vo, vo.getBaseLink(), vo.getEeLink());
|
||||||
|
// 将TransformMatrix4x4转换为Map
|
||||||
|
ArmCommand.TransformMatrix4x4 matrix = result.getMatrix();
|
||||||
|
java.util.Map<String, Object> matrixMap = new java.util.HashMap<>();
|
||||||
|
matrixMap.put("m00", matrix.getM00());
|
||||||
|
matrixMap.put("m01", matrix.getM01());
|
||||||
|
matrixMap.put("m02", matrix.getM02());
|
||||||
|
matrixMap.put("m03", matrix.getM03());
|
||||||
|
matrixMap.put("m10", matrix.getM10());
|
||||||
|
matrixMap.put("m11", matrix.getM11());
|
||||||
|
matrixMap.put("m12", matrix.getM12());
|
||||||
|
matrixMap.put("m13", matrix.getM13());
|
||||||
|
matrixMap.put("m20", matrix.getM20());
|
||||||
|
matrixMap.put("m21", matrix.getM21());
|
||||||
|
matrixMap.put("m22", matrix.getM22());
|
||||||
|
matrixMap.put("m23", matrix.getM23());
|
||||||
|
matrixMap.put("m30", matrix.getM30());
|
||||||
|
matrixMap.put("m31", matrix.getM31());
|
||||||
|
matrixMap.put("m32", matrix.getM32());
|
||||||
|
matrixMap.put("m33", matrix.getM33());
|
||||||
|
return AjaxResult.ok(matrixMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("计算正向运动学")
|
||||||
|
@PostMapping("/computeForwardKinematics")
|
||||||
|
public AjaxResult computeForwardKinematics(@RequestBody EdgeArmForwardKinematicsVO fkVO) {
|
||||||
|
ArmCommand.ComputeForwardKinematics.Response result = edgeArmService.computeForwardKinematics(
|
||||||
|
fkVO,
|
||||||
|
fkVO.getJoints(),
|
||||||
|
fkVO.getBaseLink(),
|
||||||
|
fkVO.getEeLink()
|
||||||
|
);
|
||||||
|
// 将TransformMatrix4x4转换为Map
|
||||||
|
ArmCommand.TransformMatrix4x4 matrix = result.getMatrix();
|
||||||
|
java.util.Map<String, Object> matrixMap = new java.util.HashMap<>();
|
||||||
|
matrixMap.put("m00", matrix.getM00());
|
||||||
|
matrixMap.put("m01", matrix.getM01());
|
||||||
|
matrixMap.put("m02", matrix.getM02());
|
||||||
|
matrixMap.put("m03", matrix.getM03());
|
||||||
|
matrixMap.put("m10", matrix.getM10());
|
||||||
|
matrixMap.put("m11", matrix.getM11());
|
||||||
|
matrixMap.put("m12", matrix.getM12());
|
||||||
|
matrixMap.put("m13", matrix.getM13());
|
||||||
|
matrixMap.put("m20", matrix.getM20());
|
||||||
|
matrixMap.put("m21", matrix.getM21());
|
||||||
|
matrixMap.put("m22", matrix.getM22());
|
||||||
|
matrixMap.put("m23", matrix.getM23());
|
||||||
|
matrixMap.put("m30", matrix.getM30());
|
||||||
|
matrixMap.put("m31", matrix.getM31());
|
||||||
|
matrixMap.put("m32", matrix.getM32());
|
||||||
|
matrixMap.put("m33", matrix.getM33());
|
||||||
|
return AjaxResult.ok(matrixMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,55 +0,0 @@
|
|||||||
package com.cmvr.web.controller.api;
|
|
||||||
|
|
||||||
import com.cmvr.common.core.domain.AjaxResult;
|
|
||||||
import com.cmvr.edge.client.model.EdgeCommonVO;
|
|
||||||
import com.cmvr.edge.client.model.humanoid.EdgeMoveJVO;
|
|
||||||
import com.cmvr.edge.client.model.humanoid.EdgeSpeedJVO;
|
|
||||||
import com.cmvr.edge.client.service.EdgeHumanoidRobotService;
|
|
||||||
import io.swagger.annotations.Api;
|
|
||||||
import io.swagger.annotations.ApiOperation;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
@Api(tags = "边缘--机械臂")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/humanoid")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class EdgeHumanoidRobotController {
|
|
||||||
|
|
||||||
private final EdgeHumanoidRobotService edgeHumanoidRobotService;
|
|
||||||
|
|
||||||
@ApiOperation("moveJ")
|
|
||||||
@PostMapping("/moveJ")
|
|
||||||
public AjaxResult moveJ(@RequestBody EdgeMoveJVO moveJVO) {
|
|
||||||
return AjaxResult.ok(edgeHumanoidRobotService.moveJ(moveJVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("speedJ")
|
|
||||||
@PostMapping("/speedJ")
|
|
||||||
public AjaxResult speedJ(@RequestBody EdgeSpeedJVO speedJVO) {
|
|
||||||
return AjaxResult.ok(edgeHumanoidRobotService.speedJ(speedJVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("获取关节状态")
|
|
||||||
@GetMapping("/getJointState")
|
|
||||||
public AjaxResult status(EdgeCommonVO vo) {
|
|
||||||
return AjaxResult.ok(edgeHumanoidRobotService.getJointState(vo));
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("使能开")
|
|
||||||
@GetMapping("/torqueOn")
|
|
||||||
public AjaxResult torqueOn(EdgeCommonVO vo) {
|
|
||||||
return AjaxResult.ok(edgeHumanoidRobotService.torqueOn(vo));
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("使能关")
|
|
||||||
@GetMapping("/torqueOff")
|
|
||||||
public AjaxResult torqueOff(EdgeCommonVO vo) {
|
|
||||||
return AjaxResult.ok(edgeHumanoidRobotService.torqueOff(vo));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -6,12 +6,10 @@ import com.cmvr.edge.client.model.microphone.EdgeMicrophoneVolumeVO;
|
|||||||
import com.cmvr.edge.client.service.EdgeMicrophoneService;
|
import com.cmvr.edge.client.service.EdgeMicrophoneService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 麦克风管理
|
* 麦克风管理
|
||||||
@ -27,14 +25,17 @@ public class EdgeMicrophoneController {
|
|||||||
@ApiOperation("获取麦克风状态")
|
@ApiOperation("获取麦克风状态")
|
||||||
@PreAuthorize("@ss.hasPermi('system:microphone:query')")
|
@PreAuthorize("@ss.hasPermi('system:microphone:query')")
|
||||||
@GetMapping("/status")
|
@GetMapping("/status")
|
||||||
public AjaxResult getStatus(EdgeCommonVO edgeCommonVO) {
|
public AjaxResult getStatus(@ApiParam(value = "终端设备ID", required = true) @RequestParam String terminalId, @ApiParam (value = "设备ID", required = true) @RequestParam String deviceId) {
|
||||||
|
EdgeCommonVO edgeCommonVO = new EdgeCommonVO();
|
||||||
|
edgeCommonVO.setTerminalId(terminalId);
|
||||||
|
edgeCommonVO.setDeviceId(deviceId);
|
||||||
return AjaxResult.success(microphoneService.getStatus(edgeCommonVO));
|
return AjaxResult.success(microphoneService.getStatus(edgeCommonVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("开始录音")
|
@ApiOperation("开始录音")
|
||||||
@PreAuthorize("@ss.hasPermi('system:microphone:record')")
|
@PreAuthorize("@ss.hasPermi('system:microphone:record')")
|
||||||
@PostMapping("/start")
|
@PostMapping("/start")
|
||||||
public AjaxResult startRecord(EdgeCommonVO edgeCommonVO) {
|
public AjaxResult startRecord(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||||
String filePath = microphoneService.startRecord(edgeCommonVO);
|
String filePath = microphoneService.startRecord(edgeCommonVO);
|
||||||
return AjaxResult.success(filePath);
|
return AjaxResult.success(filePath);
|
||||||
}
|
}
|
||||||
@ -42,7 +43,7 @@ public class EdgeMicrophoneController {
|
|||||||
@ApiOperation("停止录音")
|
@ApiOperation("停止录音")
|
||||||
@PreAuthorize("@ss.hasPermi('system:microphone:stop')")
|
@PreAuthorize("@ss.hasPermi('system:microphone:stop')")
|
||||||
@PostMapping("/stop")
|
@PostMapping("/stop")
|
||||||
public AjaxResult stopRecord(EdgeCommonVO edgeCommonVO) {
|
public AjaxResult stopRecord(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||||
microphoneService.stopRecord(edgeCommonVO);
|
microphoneService.stopRecord(edgeCommonVO);
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
@ -50,7 +51,7 @@ public class EdgeMicrophoneController {
|
|||||||
@ApiOperation("暂停录音")
|
@ApiOperation("暂停录音")
|
||||||
@PreAuthorize("@ss.hasPermi('system:microphone:pause')")
|
@PreAuthorize("@ss.hasPermi('system:microphone:pause')")
|
||||||
@PostMapping("/pause")
|
@PostMapping("/pause")
|
||||||
public AjaxResult pauseRecord(EdgeCommonVO edgeCommonVO) {
|
public AjaxResult pauseRecord(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||||
microphoneService.pauseRecord(edgeCommonVO);
|
microphoneService.pauseRecord(edgeCommonVO);
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
@ -58,7 +59,7 @@ public class EdgeMicrophoneController {
|
|||||||
@ApiOperation("恢复录音")
|
@ApiOperation("恢复录音")
|
||||||
@PreAuthorize("@ss.hasPermi('system:microphone:resume')")
|
@PreAuthorize("@ss.hasPermi('system:microphone:resume')")
|
||||||
@PostMapping("/resume")
|
@PostMapping("/resume")
|
||||||
public AjaxResult resumeRecord(EdgeCommonVO edgeCommonVO) {
|
public AjaxResult resumeRecord(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||||
microphoneService.resumeRecord(edgeCommonVO);
|
microphoneService.resumeRecord(edgeCommonVO);
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
@ -66,7 +67,7 @@ public class EdgeMicrophoneController {
|
|||||||
@ApiOperation("设置音量")
|
@ApiOperation("设置音量")
|
||||||
@PreAuthorize("@ss.hasPermi('system:microphone:volume')")
|
@PreAuthorize("@ss.hasPermi('system:microphone:volume')")
|
||||||
@PostMapping("/volume")
|
@PostMapping("/volume")
|
||||||
public AjaxResult setVolume(EdgeMicrophoneVolumeVO edgeMicrophoneVolumeVO) {
|
public AjaxResult setVolume(@RequestBody EdgeMicrophoneVolumeVO edgeMicrophoneVolumeVO) {
|
||||||
microphoneService.setVolume(edgeMicrophoneVolumeVO);
|
microphoneService.setVolume(edgeMicrophoneVolumeVO);
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
@ -74,7 +75,10 @@ public class EdgeMicrophoneController {
|
|||||||
@ApiOperation("获取音量")
|
@ApiOperation("获取音量")
|
||||||
@PreAuthorize("@ss.hasPermi('system:microphone:volume')")
|
@PreAuthorize("@ss.hasPermi('system:microphone:volume')")
|
||||||
@GetMapping("/volume")
|
@GetMapping("/volume")
|
||||||
public AjaxResult getVolume(EdgeCommonVO edgeCommonVO) {
|
public AjaxResult getVolume(@ApiParam(value = "终端设备ID", required = true) @RequestParam String terminalId, @ApiParam (value = "设备ID", required = true) @RequestParam String deviceId) {
|
||||||
|
EdgeCommonVO edgeCommonVO = new EdgeCommonVO();
|
||||||
|
edgeCommonVO.setTerminalId(terminalId);
|
||||||
|
edgeCommonVO.setDeviceId(deviceId);
|
||||||
return AjaxResult.success(microphoneService.getVolume(edgeCommonVO));
|
return AjaxResult.success(microphoneService.getVolume(edgeCommonVO));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,9 @@
|
|||||||
package com.cmvr.web.controller.api;
|
package com.cmvr.web.controller.api;
|
||||||
|
|
||||||
import cmvr.api.SpeakerCommand;
|
import cmvr.api.SpeakerCommand;
|
||||||
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
|
import com.cmvr.edge.client.model.microphone.EdgeMicrophoneVolumeVO;
|
||||||
|
import com.cmvr.edge.client.model.speaker.EdgeSpeakerPlayAudioVO;
|
||||||
import com.cmvr.edge.client.service.EdgeSpeakerService;
|
import com.cmvr.edge.client.service.EdgeSpeakerService;
|
||||||
import com.cmvr.common.core.domain.AjaxResult;
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
@ -69,14 +72,8 @@ public class EdgeSpeakerController {
|
|||||||
@ApiOperation("播放音频")
|
@ApiOperation("播放音频")
|
||||||
@PreAuthorize("@ss.hasPermi('system:speaker:play')")
|
@PreAuthorize("@ss.hasPermi('system:speaker:play')")
|
||||||
@PostMapping("/play")
|
@PostMapping("/play")
|
||||||
public AjaxResult playAudio(
|
public AjaxResult playAudio(@RequestBody EdgeSpeakerPlayAudioVO edgeSpeakerPlayAudioVO) {
|
||||||
@ApiParam(value = "终端设备ID", required = true)
|
speakerService.playAudio(edgeSpeakerPlayAudioVO.getTerminalId(), edgeSpeakerPlayAudioVO.getDeviceId(), edgeSpeakerPlayAudioVO.getAudioPath());
|
||||||
@RequestParam String terminalId,
|
|
||||||
@ApiParam(value = "设备ID", required = true)
|
|
||||||
@RequestParam String deviceId,
|
|
||||||
@ApiParam(value = "音频文件路径", required = true)
|
|
||||||
@RequestParam String audioPath) {
|
|
||||||
speakerService.playAudio(terminalId, deviceId, audioPath);
|
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,12 +83,8 @@ public class EdgeSpeakerController {
|
|||||||
@ApiOperation("停止播放")
|
@ApiOperation("停止播放")
|
||||||
@PreAuthorize("@ss.hasPermi('system:speaker:stop')")
|
@PreAuthorize("@ss.hasPermi('system:speaker:stop')")
|
||||||
@PostMapping("/stop")
|
@PostMapping("/stop")
|
||||||
public AjaxResult stopPlayback(
|
public AjaxResult stopPlayback(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||||
@ApiParam(value = "终端设备ID", required = true)
|
speakerService.stopPlayback(edgeCommonVO.getTerminalId(), edgeCommonVO.getDeviceId());
|
||||||
@RequestParam String terminalId,
|
|
||||||
@ApiParam(value = "设备ID", required = true)
|
|
||||||
@RequestParam String deviceId) {
|
|
||||||
speakerService.stopPlayback(terminalId, deviceId);
|
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,12 +94,8 @@ public class EdgeSpeakerController {
|
|||||||
@ApiOperation("暂停播放")
|
@ApiOperation("暂停播放")
|
||||||
@PreAuthorize("@ss.hasPermi('system:speaker:pause')")
|
@PreAuthorize("@ss.hasPermi('system:speaker:pause')")
|
||||||
@PostMapping("/pause")
|
@PostMapping("/pause")
|
||||||
public AjaxResult pausePlayback(
|
public AjaxResult pausePlayback(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||||
@ApiParam(value = "终端设备ID", required = true)
|
speakerService.pausePlayback(edgeCommonVO.getTerminalId(), edgeCommonVO.getDeviceId());
|
||||||
@RequestParam String terminalId,
|
|
||||||
@ApiParam(value = "设备ID", required = true)
|
|
||||||
@RequestParam String deviceId) {
|
|
||||||
speakerService.pausePlayback(terminalId, deviceId);
|
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,12 +105,8 @@ public class EdgeSpeakerController {
|
|||||||
@ApiOperation("恢复播放")
|
@ApiOperation("恢复播放")
|
||||||
@PreAuthorize("@ss.hasPermi('system:speaker:resume')")
|
@PreAuthorize("@ss.hasPermi('system:speaker:resume')")
|
||||||
@PostMapping("/resume")
|
@PostMapping("/resume")
|
||||||
public AjaxResult resumePlayback(
|
public AjaxResult resumePlayback(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||||
@ApiParam(value = "终端设备ID", required = true)
|
speakerService.resumePlayback(edgeCommonVO.getTerminalId(), edgeCommonVO.getDeviceId());
|
||||||
@RequestParam String terminalId,
|
|
||||||
@ApiParam(value = "设备ID", required = true)
|
|
||||||
@RequestParam String deviceId) {
|
|
||||||
speakerService.resumePlayback(terminalId, deviceId);
|
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,14 +116,8 @@ public class EdgeSpeakerController {
|
|||||||
@ApiOperation("设置音量")
|
@ApiOperation("设置音量")
|
||||||
@PreAuthorize("@ss.hasPermi('system:speaker:volume')")
|
@PreAuthorize("@ss.hasPermi('system:speaker:volume')")
|
||||||
@PostMapping("/volume")
|
@PostMapping("/volume")
|
||||||
public AjaxResult setVolume(
|
public AjaxResult setVolume(@RequestBody EdgeMicrophoneVolumeVO edgeMicrophoneVolumeVO) {
|
||||||
@ApiParam(value = "终端设备ID", required = true)
|
speakerService.setVolume(edgeMicrophoneVolumeVO.getTerminalId(), edgeMicrophoneVolumeVO.getDeviceId(), edgeMicrophoneVolumeVO.getVolume());
|
||||||
@RequestParam String terminalId,
|
|
||||||
@ApiParam(value = "设备ID", required = true)
|
|
||||||
@RequestParam String deviceId,
|
|
||||||
@ApiParam(value = "音量大小(0-100)", required = true)
|
|
||||||
@RequestParam int volume) {
|
|
||||||
speakerService.setVolume(terminalId, deviceId, volume);
|
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,123 @@
|
|||||||
|
package com.cmvr.web.controller.api;
|
||||||
|
|
||||||
|
import com.cmvr.edge.client.service.AudioService;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.socket.BinaryMessage;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
import org.springframework.web.socket.TextMessage;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||||
|
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebRTC 信令 WebSocket 入口。
|
||||||
|
*
|
||||||
|
* 路径:/ws/signaling
|
||||||
|
*
|
||||||
|
* 约束:
|
||||||
|
* 1. WebSocket 只传 JSON 信令:join、offer、answer、candidate、heartbeat、stop;
|
||||||
|
* 2. WebSocket 禁止传输 PCM 音频;
|
||||||
|
* 3. PCM 音频由 WebRTC 媒体通道进入 Java 后端,再由 AudioService 转 gRPC 双向流。
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WebRtcSignalingController implements WebSocketConfigurer {
|
||||||
|
|
||||||
|
private final AudioService audioService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||||
|
registry.addHandler(new SignalingWebSocketHandler(audioService), "/ws/signaling")
|
||||||
|
.setAllowedOrigins("*");
|
||||||
|
registry.addHandler(new SignalingWebSocketHandler(audioService), "/ws/audio")
|
||||||
|
.setAllowedOrigins("*");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 信令处理器。这里只处理文本 JSON,不处理二进制音频。
|
||||||
|
*/
|
||||||
|
private static class SignalingWebSocketHandler extends AbstractWebSocketHandler {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SignalingWebSocketHandler.class);
|
||||||
|
|
||||||
|
private final AudioService audioService;
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
private SignalingWebSocketHandler(AudioService audioService) {
|
||||||
|
this.audioService = audioService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionEstablished(@NotNull WebSocketSession session) {
|
||||||
|
log.info("WebRTC信令连接建立,wsSessionId={}", session.getId());
|
||||||
|
sendConnected(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleTextMessage(@NotNull WebSocketSession session, @NotNull TextMessage message) {
|
||||||
|
try {
|
||||||
|
audioService.handleSignalingMessage(session, message.getPayload());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理WebRTC信令异常,wsSessionId={}", session.getId(), e);
|
||||||
|
sendError(session, "处理WebRTC信令异常:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleBinaryMessage(@NotNull WebSocketSession session, @NotNull BinaryMessage message) {
|
||||||
|
try {
|
||||||
|
audioService.handleBrowserAudioMessage(session, message.getPayload());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理WebSocket音频二进制帧失败,wsSessionId={}", session.getId(), e);
|
||||||
|
sendError(session, "audio binary frame failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleTransportError(@NotNull WebSocketSession session, @NotNull Throwable exception) {
|
||||||
|
log.error("WebRTC信令连接传输异常,wsSessionId={}", session.getId(), exception);
|
||||||
|
audioService.handleWebSocketClosed(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionClosed(@NotNull WebSocketSession session, @NotNull CloseStatus status) {
|
||||||
|
log.info("WebRTC信令连接关闭,wsSessionId={},status={}", session.getId(), status);
|
||||||
|
audioService.handleWebSocketClosed(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendConnected(WebSocketSession session) {
|
||||||
|
ObjectNode node = objectMapper.createObjectNode();
|
||||||
|
node.put("type", "connected");
|
||||||
|
node.put("timestamp", System.currentTimeMillis());
|
||||||
|
sendJson(session, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendError(WebSocketSession session, String message) {
|
||||||
|
ObjectNode node = objectMapper.createObjectNode();
|
||||||
|
node.put("type", "error");
|
||||||
|
node.put("message", message);
|
||||||
|
node.put("timestamp", System.currentTimeMillis());
|
||||||
|
sendJson(session, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendJson(WebSocketSession session, ObjectNode node) {
|
||||||
|
if (session == null || !session.isOpen()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
synchronized (session) {
|
||||||
|
session.sendMessage(new TextMessage(objectMapper.writeValueAsString(node)));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送WebRTC信令响应失败,wsSessionId={}", session.getId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
package com.cmvr.web.controller.inspection;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.inspection.domain.InspectionAlarm;
|
||||||
|
import com.cmvr.inspection.domain.vo.InspectionAlarmVo;
|
||||||
|
import com.cmvr.inspection.service.IInspectionAlarmService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡检告警Controller
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-05-29
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/inspection/alarm")
|
||||||
|
@Api(tags = "智能巡检--告警管理")
|
||||||
|
public class InspectionAlarmController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IInspectionAlarmService inspectionAlarmService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询巡检告警列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询巡检告警列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:alarm:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(InspectionAlarm inspectionAlarm)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<InspectionAlarmVo> list = inspectionAlarmService.selectInspectionAlarmList(inspectionAlarm);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出巡检告警列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("导出巡检告警列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:alarm:export')")
|
||||||
|
@Log(title = "巡检告警", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, InspectionAlarm inspectionAlarm)
|
||||||
|
{
|
||||||
|
List<InspectionAlarmVo> list = inspectionAlarmService.selectInspectionAlarmList(inspectionAlarm);
|
||||||
|
ExcelUtil<InspectionAlarmVo> util = new ExcelUtil<>(InspectionAlarmVo.class);
|
||||||
|
util.exportExcel(response, list, "巡检告警数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取巡检告警详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取巡检告警详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:alarm:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||||
|
{
|
||||||
|
return success(inspectionAlarmService.selectInspectionAlarmById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增巡检告警
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增巡检告警")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:alarm:add')")
|
||||||
|
@Log(title = "巡检告警", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody InspectionAlarm inspectionAlarm)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionAlarmService.insertInspectionAlarm(inspectionAlarm));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改巡检告警
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改巡检告警")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:alarm:edit')")
|
||||||
|
@Log(title = "巡检告警", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody InspectionAlarm inspectionAlarm)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionAlarmService.updateInspectionAlarm(inspectionAlarm));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除巡检告警
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除巡检告警")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:alarm:remove')")
|
||||||
|
@Log(title = "巡检告警", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionAlarmService.deleteInspectionAlarmByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,123 @@
|
|||||||
|
package com.cmvr.web.controller.inspection;
|
||||||
|
|
||||||
|
import com.cmvr.common.annotation.Anonymous;
|
||||||
|
import com.cmvr.inspection.domain.dto.alert.AlertEnvelope;
|
||||||
|
import com.cmvr.inspection.exception.DetectionAlertBadRequestException;
|
||||||
|
import com.cmvr.inspection.service.IInspectionDetectionAlertService;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestHeader;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.servlet.ServletInputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cmvr_edge_ai 检测报警推送入口。
|
||||||
|
*
|
||||||
|
* 该接口由边缘服务主动调用,使用HTTP状态码表达处理结果,不使用项目通用AjaxResult包装。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Anonymous
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Api(tags = "智能巡检--PPE报警接收")
|
||||||
|
public class InspectionDetectionAlertController
|
||||||
|
{
|
||||||
|
/** 包含Base64图片的JSON请求最大允许20MB,防止异常请求耗尽服务端内存。 */
|
||||||
|
private static final int MAX_REQUEST_BYTES = 20 * 1024 * 1024;
|
||||||
|
|
||||||
|
private final IInspectionDetectionAlertService detectionAlertService;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收PPE违规报警。重复事件视为已处理,仍返回204,避免边缘端持续重试。
|
||||||
|
*/
|
||||||
|
@ApiOperation("接收边缘AI的PPE违规报警")
|
||||||
|
@PostMapping(value = "/v1/detection-alerts", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<Void> receive(
|
||||||
|
@RequestHeader(value = "Idempotency-Key", required = false) String idempotencyKey,
|
||||||
|
HttpServletRequest request)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String requestBody = readRequestBody(request);
|
||||||
|
AlertEnvelope envelope = objectMapper.readValue(requestBody, AlertEnvelope.class);
|
||||||
|
detectionAlertService.receive(envelope, idempotencyKey);
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
}
|
||||||
|
catch (JsonProcessingException | DetectionAlertBadRequestException ex)
|
||||||
|
{
|
||||||
|
log.warn("拒绝不合法的PPE报警请求,idempotencyKey={},原因={}", idempotencyKey, ex.getMessage());
|
||||||
|
return ResponseEntity.badRequest().build();
|
||||||
|
}
|
||||||
|
catch (DuplicateKeyException ex)
|
||||||
|
{
|
||||||
|
// 预查与插入之间仍可能发生并发,由数据库唯一索引完成最终幂等。
|
||||||
|
log.info("忽略并发重复的PPE报警,idempotencyKey={}", idempotencyKey);
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
log.warn("读取PPE报警请求失败,idempotencyKey={},原因={}", idempotencyKey, ex.getMessage());
|
||||||
|
return ResponseEntity.badRequest().build();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
log.error("PPE报警处理暂时失败,idempotencyKey={}", idempotencyKey, ex);
|
||||||
|
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readRequestBody(HttpServletRequest request) throws IOException
|
||||||
|
{
|
||||||
|
long contentLength = request.getContentLengthLong();
|
||||||
|
if (contentLength > MAX_REQUEST_BYTES)
|
||||||
|
{
|
||||||
|
throw new DetectionAlertBadRequestException("请求体不能超过20MB");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (ServletInputStream inputStream = request.getInputStream();
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(initialCapacity(contentLength)))
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int total = 0;
|
||||||
|
int length;
|
||||||
|
while ((length = inputStream.read(buffer)) != -1)
|
||||||
|
{
|
||||||
|
total += length;
|
||||||
|
if (total > MAX_REQUEST_BYTES)
|
||||||
|
{
|
||||||
|
throw new DetectionAlertBadRequestException("请求体不能超过20MB");
|
||||||
|
}
|
||||||
|
outputStream.write(buffer, 0, length);
|
||||||
|
}
|
||||||
|
if (total == 0)
|
||||||
|
{
|
||||||
|
throw new DetectionAlertBadRequestException("请求体不能为空");
|
||||||
|
}
|
||||||
|
return new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int initialCapacity(long contentLength)
|
||||||
|
{
|
||||||
|
if (contentLength <= 0 || contentLength > MAX_REQUEST_BYTES)
|
||||||
|
{
|
||||||
|
return 8192;
|
||||||
|
}
|
||||||
|
return (int) contentLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
package com.cmvr.web.controller.inspection;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.inspection.domain.InspectionMap;
|
||||||
|
import com.cmvr.inspection.domain.vo.InspectionMapVo;
|
||||||
|
import com.cmvr.inspection.service.IInspectionMapService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡检地图Controller
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-05-29
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/inspection/map")
|
||||||
|
@Api(tags = "智能巡检--地图管理")
|
||||||
|
public class InspectionMapController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IInspectionMapService inspectionMapService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询巡检地图列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询巡检地图列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:map:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(InspectionMap inspectionMap)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<InspectionMapVo> list = inspectionMapService.selectInspectionMapList(inspectionMap);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出巡检地图列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("导出巡检地图列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:map:export')")
|
||||||
|
@Log(title = "巡检地图", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, InspectionMap inspectionMap)
|
||||||
|
{
|
||||||
|
List<InspectionMapVo> list = inspectionMapService.selectInspectionMapList(inspectionMap);
|
||||||
|
ExcelUtil<InspectionMapVo> util = new ExcelUtil<>(InspectionMapVo.class);
|
||||||
|
util.exportExcel(response, list, "巡检地图数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取巡检地图详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取巡检地图详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:map:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||||
|
{
|
||||||
|
return success(inspectionMapService.selectInspectionMapById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增巡检地图
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增巡检地图")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:map:add')")
|
||||||
|
@Log(title = "巡检地图", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody InspectionMap inspectionMap)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionMapService.insertInspectionMap(inspectionMap));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改巡检地图
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改巡检地图")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:map:edit')")
|
||||||
|
@Log(title = "巡检地图", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody InspectionMap inspectionMap)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionMapService.updateInspectionMap(inspectionMap));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除巡检地图
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除巡检地图")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:map:remove')")
|
||||||
|
@Log(title = "巡检地图", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionMapService.deleteInspectionMapByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,126 @@
|
|||||||
|
package com.cmvr.web.controller.inspection;
|
||||||
|
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.inspection.domain.dto.InspectionResultQuery;
|
||||||
|
import com.cmvr.inspection.domain.dto.InspectionResultReviewRequest;
|
||||||
|
import com.cmvr.inspection.domain.vo.InspectionResultVo;
|
||||||
|
import com.cmvr.inspection.service.IInspectionResultService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
|
import io.swagger.annotations.ApiImplicitParams;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
|
import io.swagger.annotations.ApiResponse;
|
||||||
|
import io.swagger.annotations.ApiResponses;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡检结果、人工复核和任务报表接口。
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/inspection/result")
|
||||||
|
@Api(tags = "智能巡检--巡检结果", description = "巡检结果查询、人工复核、三级告警统计和报表导出")
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(code = 200, message = "请求处理成功"),
|
||||||
|
@ApiResponse(code = 400, message = "请求参数或状态不合法"),
|
||||||
|
@ApiResponse(code = 401, message = "未登录或登录已失效"),
|
||||||
|
@ApiResponse(code = 403, message = "无接口权限"),
|
||||||
|
@ApiResponse(code = 500, message = "系统内部异常")
|
||||||
|
})
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class InspectionResultController extends BaseController
|
||||||
|
{
|
||||||
|
private final IInspectionResultService inspectionResultService;
|
||||||
|
|
||||||
|
@ApiOperation(value = "查询巡检结果列表",
|
||||||
|
notes = "分页查询PPE、仪表读数和人工判断结果;查询条件均为可选,结果按检测时间倒序。"
|
||||||
|
+ "返回rows元素为InspectionResultVo,包含taskName任务名称和evidenceType主要证据类型;"
|
||||||
|
+ "完整mediaList仅在详情接口返回")
|
||||||
|
@ApiImplicitParams({
|
||||||
|
@ApiImplicitParam(name = "pageNum", value = "页码,从1开始", dataType = "int", paramType = "query", example = "1"),
|
||||||
|
@ApiImplicitParam(name = "pageSize", value = "每页数量", dataType = "int", paramType = "query", example = "10"),
|
||||||
|
@ApiImplicitParam(name = "taskInstanceId", value = "巡检任务实例数据库ID", dataType = "string", paramType = "query"),
|
||||||
|
@ApiImplicitParam(name = "taskId", value = "巡检任务ID", dataType = "string", paramType = "query"),
|
||||||
|
@ApiImplicitParam(name = "itemId", value = "检测项ID", dataType = "string", paramType = "query"),
|
||||||
|
@ApiImplicitParam(name = "resultType", value = "结果类型:PPE、METER、MANUAL", dataType = "string", paramType = "query"),
|
||||||
|
@ApiImplicitParam(name = "resultStatus", value = "状态:PENDING、NORMAL、ABNORMAL、RECOGNIZE_FAILED", dataType = "string", paramType = "query"),
|
||||||
|
@ApiImplicitParam(name = "alarmLevel", value = "告警级别:1提示、2警告、3严重", dataType = "int", paramType = "query"),
|
||||||
|
@ApiImplicitParam(name = "resultName", value = "检查名称,支持模糊查询", dataType = "string", paramType = "query")
|
||||||
|
})
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:result:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(@ApiParam("巡检结果查询条件") InspectionResultQuery query)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
return getDataTable(inspectionResultService.selectResultList(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "查询巡检结果详情",
|
||||||
|
notes = "返回结构化巡检结果及按顺序排列的全部图片、视频证据",
|
||||||
|
response = InspectionResultVo.class)
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:result:query')")
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public AjaxResult getInfo(@ApiParam(value = "巡检结果ID", required = true)
|
||||||
|
@PathVariable String id)
|
||||||
|
{
|
||||||
|
return success(inspectionResultService.selectResultById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "提交人工复核结果",
|
||||||
|
notes = "仅PENDING或RECOGNIZE_FAILED状态可复核。ABNORMAL必须传alarmLevel;reviewVersion用于并发控制")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:result:review')")
|
||||||
|
@Log(title = "巡检结果人工复核", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/{id}/review")
|
||||||
|
public AjaxResult review(@ApiParam(value = "巡检结果ID", required = true)
|
||||||
|
@PathVariable String id,
|
||||||
|
@ApiParam(value = "人工复核内容", required = true)
|
||||||
|
@Validated @RequestBody InspectionResultReviewRequest request)
|
||||||
|
{
|
||||||
|
return success(inspectionResultService.review(id, request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "查询巡检任务报表汇总",
|
||||||
|
notes = "返回summary统计和results明细。reviewCompleted=false表示仍有待复核或识别失败结果")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:result:report')")
|
||||||
|
@GetMapping("/report/{taskInstanceId}")
|
||||||
|
public AjaxResult report(@ApiParam(value = "巡检任务实例数据库ID", required = true)
|
||||||
|
@PathVariable String taskInstanceId)
|
||||||
|
{
|
||||||
|
AjaxResult result = AjaxResult.success();
|
||||||
|
result.put("summary", inspectionResultService.buildReportSummary(taskInstanceId));
|
||||||
|
InspectionResultQuery query = new InspectionResultQuery();
|
||||||
|
query.setTaskInstanceId(taskInstanceId);
|
||||||
|
result.put("results", inspectionResultService.selectResultList(query));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "导出巡检结果报表",
|
||||||
|
notes = "按查询条件导出Excel;不传条件时导出全部巡检结果")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:result:export')")
|
||||||
|
@Log(title = "巡检结果", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response,
|
||||||
|
@ApiParam("导出筛选条件") InspectionResultQuery query)
|
||||||
|
{
|
||||||
|
List<InspectionResultVo> list = inspectionResultService.selectResultList(query);
|
||||||
|
ExcelUtil<InspectionResultVo> util = new ExcelUtil<>(InspectionResultVo.class);
|
||||||
|
util.exportExcel(response, list, "巡检结果数据");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,241 @@
|
|||||||
|
package com.cmvr.web.controller.inspection;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import cmvr.msgs.Agv;
|
||||||
|
import com.cmvr.inspection.domain.vo.InspectionRobotVo;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.inspection.domain.InspectionRobot;
|
||||||
|
import com.cmvr.inspection.service.IInspectionRobotService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡检机器人Controller
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-05-29
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/inspection/robot")
|
||||||
|
@Api(tags = "智能巡检--机器人管理")
|
||||||
|
public class InspectionRobotController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IInspectionRobotService inspectionRobotService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询巡检机器人列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询巡检机器人列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(InspectionRobot inspectionRobot)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<InspectionRobotVo> list = inspectionRobotService.selectInspectionRobotList(inspectionRobot);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出巡检机器人列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("导出巡检机器人列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:export')")
|
||||||
|
@Log(title = "巡检机器人", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, InspectionRobot inspectionRobot)
|
||||||
|
{
|
||||||
|
List<InspectionRobotVo> list = inspectionRobotService.selectInspectionRobotList(inspectionRobot);
|
||||||
|
ExcelUtil<InspectionRobotVo> util = new ExcelUtil<>(InspectionRobotVo.class);
|
||||||
|
util.exportExcel(response, list, "巡检机器人数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取巡检机器人详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取巡检机器人详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||||
|
{
|
||||||
|
return success(inspectionRobotService.selectInspectionRobotById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增巡检机器人
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增巡检机器人")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:add')")
|
||||||
|
@Log(title = "巡检机器人", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody InspectionRobot inspectionRobot)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionRobotService.insertInspectionRobot(inspectionRobot));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改巡检机器人
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改巡检机器人")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:edit')")
|
||||||
|
@Log(title = "巡检机器人", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody InspectionRobot inspectionRobot)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionRobotService.updateInspectionRobot(inspectionRobot));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除巡检机器人
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除巡检机器人")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:remove')")
|
||||||
|
@Log(title = "巡检机器人", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionRobotService.deleteInspectionRobotByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取机器人地图列表(从AGV获取)
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取机器人地图列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:query')")
|
||||||
|
@GetMapping("/{robotId}/maps")
|
||||||
|
public AjaxResult getRobotMapList(@PathVariable String robotId)
|
||||||
|
{
|
||||||
|
List<String> robotMapList = inspectionRobotService.getRobotMapList(robotId);
|
||||||
|
return success(robotMapList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定机器人地图
|
||||||
|
*/
|
||||||
|
@ApiOperation("绑定机器人地图")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:edit')")
|
||||||
|
@Log(title = "绑定机器人地图", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/{robotId}/bind-map/{mapId}")
|
||||||
|
public AjaxResult bindRobotMap(@PathVariable String robotId,
|
||||||
|
@PathVariable String mapId)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionRobotService.bindRobotMap(robotId, mapId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从机器人下载地图
|
||||||
|
*/
|
||||||
|
@ApiOperation("从机器人下载地图")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:add')")
|
||||||
|
@Log(title = "从机器人下载地图", businessType = BusinessType.INSERT)
|
||||||
|
@GetMapping("/{robotId}/download-map")
|
||||||
|
public AjaxResult downloadMapFromRobot(
|
||||||
|
@PathVariable @ApiParam("机器人ID") String robotId,
|
||||||
|
@RequestParam(value = "mapName") @ApiParam("地图名称") String mapName
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Object mapId = inspectionRobotService.downloadMapFromRobot(robotId, mapName);
|
||||||
|
return success(mapId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传地图(从源机器人下载到目标机器人)
|
||||||
|
*/
|
||||||
|
@ApiOperation("上传地图到机器人")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:edit')")
|
||||||
|
@Log(title = "上传地图到机器人", businessType = BusinessType.OTHER)
|
||||||
|
@PostMapping("/{robotId}/upload-map-from-source")
|
||||||
|
public AjaxResult uploadMapFromSource(@PathVariable String robotId)
|
||||||
|
{
|
||||||
|
String result = inspectionRobotService.uploadMapFromSource(robotId);
|
||||||
|
return success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步机器人状态
|
||||||
|
*/
|
||||||
|
@ApiOperation("同步机器人状态")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:edit')")
|
||||||
|
@Log(title = "同步机器人状态", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/{robotId}/sync-status")
|
||||||
|
public AjaxResult syncRobotStatus(@PathVariable String robotId)
|
||||||
|
{
|
||||||
|
return success(inspectionRobotService.syncRobotStatus(robotId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取机器人实时位置
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取机器人实时位置")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:query')")
|
||||||
|
@GetMapping("/{robotId}/location")
|
||||||
|
public AjaxResult getRobotRealtimeLocation(@PathVariable String robotId)
|
||||||
|
{
|
||||||
|
Agv.AgvPose2d location = inspectionRobotService.getRobotRealtimeLocation(robotId);
|
||||||
|
return success(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航到指定位置(坐标)
|
||||||
|
*/
|
||||||
|
@ApiOperation("导航到指定位置")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:edit')")
|
||||||
|
@Log(title = "导航到指定位置", businessType = BusinessType.OTHER)
|
||||||
|
@PostMapping("/{robotId}/navigate-to-position")
|
||||||
|
public AjaxResult navigateToPosition(
|
||||||
|
@PathVariable @ApiParam("机器人ID") String robotId,
|
||||||
|
@RequestParam @ApiParam("X坐标(米)") Double x,
|
||||||
|
@RequestParam @ApiParam("Y坐标(米)") Double y,
|
||||||
|
@RequestParam(required = false) @ApiParam("朝向角(弧度)") Double theta
|
||||||
|
)
|
||||||
|
{
|
||||||
|
inspectionRobotService.navigateToPosition(
|
||||||
|
robotId, x, y, theta
|
||||||
|
);
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始建图
|
||||||
|
*/
|
||||||
|
@ApiOperation("开始建图")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:edit')")
|
||||||
|
@Log(title = "开始建图", businessType = BusinessType.OTHER)
|
||||||
|
@PostMapping("/{robotId}/start-mapping")
|
||||||
|
public AjaxResult startMapping(
|
||||||
|
@PathVariable @ApiParam("机器人ID") String robotId,
|
||||||
|
@RequestParam @ApiParam("建图维度(0:未指定 1:2D 2:3D 3:2D+3D)") int dimension,
|
||||||
|
@RequestParam(required = false) @ApiParam("地图名称(可选)") String mapName,
|
||||||
|
@RequestParam(defaultValue = "true") @ApiParam("是否实时建图") boolean realTime
|
||||||
|
)
|
||||||
|
{
|
||||||
|
String sessionId = inspectionRobotService.startMapping(robotId, dimension, mapName, realTime);
|
||||||
|
java.util.Map<String, Object> result = new java.util.HashMap<>();
|
||||||
|
result.put("sessionId", sessionId);
|
||||||
|
return success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止建图
|
||||||
|
*/
|
||||||
|
@ApiOperation("停止建图")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:edit')")
|
||||||
|
@Log(title = "停止建图", businessType = BusinessType.OTHER)
|
||||||
|
@PostMapping("/{robotId}/stop-mapping")
|
||||||
|
public AjaxResult stopMapping(@PathVariable @ApiParam("机器人ID") String robotId)
|
||||||
|
{
|
||||||
|
inspectionRobotService.stopMapping(robotId);
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,151 @@
|
|||||||
|
package com.cmvr.web.controller.inspection;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.inspection.domain.InspectionTask;
|
||||||
|
import com.cmvr.inspection.domain.InspectionWaypoint;
|
||||||
|
import com.cmvr.inspection.domain.vo.InspectionTaskVo;
|
||||||
|
import com.cmvr.inspection.service.IInspectionTaskService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡检任务Controller
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-05-29
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/inspection/task")
|
||||||
|
@Api(tags = "智能巡检--任务管理")
|
||||||
|
public class InspectionTaskController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IInspectionTaskService inspectionTaskService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询巡检任务列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询巡检任务列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:task:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(InspectionTask inspectionTask)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<InspectionTaskVo> list = inspectionTaskService.selectInspectionTaskList(inspectionTask);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出巡检任务列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("导出巡检任务列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:task:export')")
|
||||||
|
@Log(title = "巡检任务", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, InspectionTask inspectionTask)
|
||||||
|
{
|
||||||
|
List<InspectionTaskVo> list = inspectionTaskService.selectInspectionTaskList(inspectionTask);
|
||||||
|
ExcelUtil<InspectionTaskVo> util = new ExcelUtil<>(InspectionTaskVo.class);
|
||||||
|
util.exportExcel(response, list, "巡检任务数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取巡检任务详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取巡检任务详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:task:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||||
|
{
|
||||||
|
return success(inspectionTaskService.selectInspectionTaskById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增巡检任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增巡检任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:task:add')")
|
||||||
|
@Log(title = "巡检任务", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody InspectionTask inspectionTask)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskService.insertInspectionTask(inspectionTask));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改巡检任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改巡检任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:task:edit')")
|
||||||
|
@Log(title = "巡检任务", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody InspectionTask inspectionTask)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskService.updateInspectionTask(inspectionTask));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除巡检任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除巡检任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:task:remove')")
|
||||||
|
@Log(title = "巡检任务", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskService.deleteInspectionTaskByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询任务关联的点位列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询任务关联的点位列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:task:query')")
|
||||||
|
@GetMapping("/{taskId}/waypoints")
|
||||||
|
public AjaxResult getWaypoints(@PathVariable("taskId") String taskId)
|
||||||
|
{
|
||||||
|
List<InspectionWaypoint> list = inspectionTaskService.selectWaypointsByTaskId(taskId);
|
||||||
|
return success(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定点位到任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("绑定点位到任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:task:edit')")
|
||||||
|
@Log(title = "巡检任务", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/{taskId}/waypoints")
|
||||||
|
public AjaxResult bindWaypoints(@PathVariable("taskId") String taskId, @RequestBody String[] waypointIds)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskService.bindWaypoints(taskId, waypointIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解绑任务的点位
|
||||||
|
*/
|
||||||
|
@ApiOperation("解绑任务的点位")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:task:edit')")
|
||||||
|
@Log(title = "巡检任务", businessType = BusinessType.UPDATE)
|
||||||
|
@DeleteMapping("/{taskId}/waypoints")
|
||||||
|
public AjaxResult unbindWaypoints(@PathVariable("taskId") String taskId)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskService.unbindWaypoints(taskId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,164 @@
|
|||||||
|
package com.cmvr.web.controller.inspection;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import com.cmvr.inspection.domain.dto.InspectionTaskInstanceQuery;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.inspection.domain.InspectionTaskInstance;
|
||||||
|
import com.cmvr.inspection.domain.vo.InspectionTaskInstanceVo;
|
||||||
|
import com.cmvr.inspection.service.IInspectionTaskInstanceService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡检任务执行实例Controller
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-01
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/inspection/taskInstance")
|
||||||
|
@Api(tags = "智能巡检--任务执行实例管理")
|
||||||
|
public class InspectionTaskInstanceController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IInspectionTaskInstanceService inspectionTaskInstanceService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询巡检任务执行实例列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询巡检任务执行实例列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:taskInstance:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(InspectionTaskInstanceQuery inspectionTaskInstanceQuery)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<InspectionTaskInstanceVo> list = inspectionTaskInstanceService.selectInspectionTaskInstanceList(inspectionTaskInstanceQuery);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出巡检任务执行实例列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("导出巡检任务执行实例列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:taskInstance:export')")
|
||||||
|
@Log(title = "巡检任务执行实例", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, InspectionTaskInstanceQuery inspectionTaskInstanceQuery)
|
||||||
|
{
|
||||||
|
List<InspectionTaskInstanceVo> list = inspectionTaskInstanceService.selectInspectionTaskInstanceList(inspectionTaskInstanceQuery);
|
||||||
|
ExcelUtil<InspectionTaskInstanceVo> util = new ExcelUtil<>(InspectionTaskInstanceVo.class);
|
||||||
|
util.exportExcel(response, list, "巡检任务执行实例数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取巡检任务执行实例详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取巡检任务执行实例详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:taskInstance:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||||
|
{
|
||||||
|
return success(inspectionTaskInstanceService.selectInspectionTaskInstanceVoById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增巡检任务执行实例
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增巡检任务执行实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:taskInstance:add')")
|
||||||
|
@Log(title = "巡检任务执行实例", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody InspectionTaskInstance inspectionTaskInstance)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskInstanceService.insertInspectionTaskInstance(inspectionTaskInstance));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改巡检任务执行实例
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改巡检任务执行实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:taskInstance:edit')")
|
||||||
|
@Log(title = "巡检任务执行实例", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody InspectionTaskInstance inspectionTaskInstance)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskInstanceService.updateInspectionTaskInstance(inspectionTaskInstance));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除巡检任务执行实例
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除巡检任务执行实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:taskInstance:remove')")
|
||||||
|
@Log(title = "巡检任务执行实例", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskInstanceService.deleteInspectionTaskInstanceByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始执行任务实例
|
||||||
|
*/
|
||||||
|
@ApiOperation("开始执行任务实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:taskInstance:edit')")
|
||||||
|
@Log(title = "巡检任务执行实例", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/start/{id}")
|
||||||
|
public AjaxResult start(@PathVariable("id") String id)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskInstanceService.startInstance(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停任务实例
|
||||||
|
*/
|
||||||
|
@ApiOperation("暂停任务实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:taskInstance:edit')")
|
||||||
|
@Log(title = "巡检任务执行实例", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/pause/{id}")
|
||||||
|
public AjaxResult pause(@PathVariable("id") String id)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskInstanceService.pauseInstance(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终止任务实例
|
||||||
|
*/
|
||||||
|
@ApiOperation("终止任务实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:taskInstance:edit')")
|
||||||
|
@Log(title = "巡检任务执行实例", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/stop/{id}")
|
||||||
|
public AjaxResult stop(@PathVariable("id") String id)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskInstanceService.stopInstance(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复任务实例
|
||||||
|
*/
|
||||||
|
@ApiOperation("恢复任务实例")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:taskInstance:edit')")
|
||||||
|
@Log(title = "巡检任务执行实例", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/resume/{id}")
|
||||||
|
public AjaxResult resume(@PathVariable("id") String id)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionTaskInstanceService.resumeInstance(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
package com.cmvr.web.controller.inspection;
|
||||||
|
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.inspection.domain.InspectionTaskLog;
|
||||||
|
import com.cmvr.inspection.service.IInspectionTaskLogService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡检任务执行日志Controller
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-05
|
||||||
|
*/
|
||||||
|
@Api(tags = "智能巡检-巡检任务执行日志管理")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/inspection/taskLog")
|
||||||
|
public class InspectionTaskLogController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IInspectionTaskLogService inspectionTaskLogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询巡检任务执行日志列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询巡检任务执行日志列表")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(@ApiParam("任务实例ID") @RequestParam String taskInstanceId) {
|
||||||
|
List<InspectionTaskLog> list = inspectionTaskLogService.selectInspectionTaskLogList(taskInstanceId);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取巡检任务执行日志详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取巡检任务执行日志详细信息")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@ApiParam("日志ID") @PathVariable("id") String id) {
|
||||||
|
return success(inspectionTaskLogService.getById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增巡检任务执行日志
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增巡检任务执行日志")
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody InspectionTaskLog inspectionTaskLog) {
|
||||||
|
return toAjax(inspectionTaskLogService.insertInspectionTaskLog(inspectionTaskLog));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增巡检任务执行日志
|
||||||
|
*/
|
||||||
|
@ApiOperation("批量新增巡检任务执行日志")
|
||||||
|
@PostMapping("/batch")
|
||||||
|
public AjaxResult batchAdd(@RequestBody List<InspectionTaskLog> logList) {
|
||||||
|
return toAjax(inspectionTaskLogService.batchInsertInspectionTaskLog(logList));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改巡检任务执行日志
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改巡检任务执行日志")
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody InspectionTaskLog inspectionTaskLog) {
|
||||||
|
return toAjax(inspectionTaskLogService.updateById(inspectionTaskLog));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除巡检任务执行日志
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除巡检任务执行日志")
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@ApiParam("日志ID数组") @PathVariable String[] ids) {
|
||||||
|
return toAjax(inspectionTaskLogService.removeByIds(java.util.Arrays.asList(ids)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
package com.cmvr.web.controller.inspection;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.inspection.domain.InspectionWaypoint;
|
||||||
|
import com.cmvr.inspection.domain.vo.InspectionWaypointVo;
|
||||||
|
import com.cmvr.inspection.service.IInspectionWaypointService;
|
||||||
|
import com.cmvr.common.utils.poi.ExcelUtil;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡检点位Controller
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-05-29
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/inspection/waypoint")
|
||||||
|
@Api(tags = "智能巡检--点位管理")
|
||||||
|
public class InspectionWaypointController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IInspectionWaypointService inspectionWaypointService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询巡检点位列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询巡检点位列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:waypoint:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(InspectionWaypoint inspectionWaypoint)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<InspectionWaypointVo> list = inspectionWaypointService.selectInspectionWaypointList(inspectionWaypoint);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出巡检点位列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("导出巡检点位列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:waypoint:export')")
|
||||||
|
@Log(title = "巡检点位", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, InspectionWaypoint inspectionWaypoint)
|
||||||
|
{
|
||||||
|
List<InspectionWaypointVo> list = inspectionWaypointService.selectInspectionWaypointList(inspectionWaypoint);
|
||||||
|
ExcelUtil<InspectionWaypointVo> util = new ExcelUtil<>(InspectionWaypointVo.class);
|
||||||
|
util.exportExcel(response, list, "巡检点位数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取巡检点位详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取巡检点位详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:waypoint:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||||
|
{
|
||||||
|
return success(inspectionWaypointService.selectInspectionWaypointById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增巡检点位
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增巡检点位")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:waypoint:add')")
|
||||||
|
@Log(title = "巡检点位", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody InspectionWaypoint inspectionWaypoint)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionWaypointService.insertInspectionWaypoint(inspectionWaypoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改巡检点位
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改巡检点位")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:waypoint:edit')")
|
||||||
|
@Log(title = "巡检点位", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody InspectionWaypoint inspectionWaypoint)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionWaypointService.updateInspectionWaypoint(inspectionWaypoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除巡检点位
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除巡检点位")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:waypoint:remove')")
|
||||||
|
@Log(title = "巡检点位", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(inspectionWaypointService.deleteInspectionWaypointByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,7 +1,12 @@
|
|||||||
package com.cmvr.web.controller.test;
|
package com.cmvr.web.controller.test;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.cmvr.common.annotation.Anonymous;
|
||||||
import com.cmvr.common.core.controller.BaseController;
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
import com.cmvr.common.core.domain.AjaxResult;
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.llm.service.LLMAiAgentPlatformService;
|
||||||
import com.cmvr.test.flow.context.TaskContextManager;
|
import com.cmvr.test.flow.context.TaskContextManager;
|
||||||
import com.cmvr.test.flow.control.FlowControlService;
|
import com.cmvr.test.flow.control.FlowControlService;
|
||||||
import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService;
|
import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService;
|
||||||
@ -25,7 +30,15 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
@Api(tags = "测试--流程服务")
|
@Api(tags = "测试--流程服务")
|
||||||
@RestController
|
@RestController
|
||||||
@ -33,6 +46,21 @@ import javax.validation.Valid;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class TeFlowController extends BaseController {
|
public class TeFlowController extends BaseController {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTS 播放接口,当前按需求固定写死在 Controller 中。
|
||||||
|
*/
|
||||||
|
private static final String TTS_PLAY_URL = "http://localhost:8080/tts/play";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTS 停止接口,停止智能体输出时同步调用。
|
||||||
|
*/
|
||||||
|
private static final String TTS_STOP_URL = "http://localhost:8080/tts/stop";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商道智能体 AppKey,当前按需求固定写死,不放入配置文件。
|
||||||
|
*/
|
||||||
|
private static final String AI_AGENT_API_KEY = "d9etum54shheenol3apg";
|
||||||
|
|
||||||
private final ITeDetectionItemService teDetectionItemService;
|
private final ITeDetectionItemService teDetectionItemService;
|
||||||
private final ITeNodeInstService nodeInstService;
|
private final ITeNodeInstService nodeInstService;
|
||||||
private final FlowTaskRuntimeService flowTaskRuntimeService;
|
private final FlowTaskRuntimeService flowTaskRuntimeService;
|
||||||
@ -40,6 +68,22 @@ public class TeFlowController extends BaseController {
|
|||||||
private final FlowControlService flowControlService;
|
private final FlowControlService flowControlService;
|
||||||
private final FlowActionExecutorService flowActionExecutorService;
|
private final FlowActionExecutorService flowActionExecutorService;
|
||||||
private final TiTouchOperateService tiTouchOperateService;
|
private final TiTouchOperateService tiTouchOperateService;
|
||||||
|
private final LLMAiAgentPlatformService llmAiAgentPlatformService;
|
||||||
|
private final List<String> taskInstIdList = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 智能体调用是阻塞式 query,这里用单线程保存当前任务句柄,便于 stop 接口中断当前请求。
|
||||||
|
*/
|
||||||
|
private final ExecutorService aiAgentExecutor = Executors.newSingleThreadExecutor(runnable -> {
|
||||||
|
Thread thread = new Thread(runnable, "flow-ai-agent-query");
|
||||||
|
thread.setDaemon(true);
|
||||||
|
return thread;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前正在执行的智能体任务。当前接口按“同一时间只保留一个前端智能体调用”处理。
|
||||||
|
*/
|
||||||
|
private volatile Future<JSONObject> currentAiAgentFuture;
|
||||||
|
|
||||||
@ApiOperation("流程发布")
|
@ApiOperation("流程发布")
|
||||||
@PostMapping("/publish")
|
@PostMapping("/publish")
|
||||||
@ -47,8 +91,26 @@ public class TeFlowController extends BaseController {
|
|||||||
return toAjax(teDetectionItemService.publish(detectionItem.getId()));
|
return toAjax(teDetectionItemService.publish(detectionItem.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiOperation("演示任务执行入口")
|
||||||
|
@PostMapping("/demo")
|
||||||
|
@Anonymous
|
||||||
|
public AjaxResult demo(@Valid @RequestBody TeTaskExecuteNormalVO taskExecuteNormalVO) {
|
||||||
|
if (!taskInstIdList.isEmpty()) {
|
||||||
|
try {
|
||||||
|
taskInstIdList.forEach(flowControlService::stop);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 演示入口清理旧任务失败时继续启动新任务,避免影响手动调试。
|
||||||
|
}
|
||||||
|
taskInstIdList.clear();
|
||||||
|
}
|
||||||
|
String insId = flowTaskRuntimeService.executeTask(taskExecuteNormalVO);
|
||||||
|
taskInstIdList.add(insId);
|
||||||
|
return AjaxResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
@ApiOperation("任务执行入口")
|
@ApiOperation("任务执行入口")
|
||||||
@PostMapping("/execute")
|
@PostMapping("/execute")
|
||||||
|
@Anonymous
|
||||||
public AjaxResult execute(@Valid @RequestBody TeTaskExecuteNormalVO taskExecuteNormalVO) {
|
public AjaxResult execute(@Valid @RequestBody TeTaskExecuteNormalVO taskExecuteNormalVO) {
|
||||||
return AjaxResult.success(flowTaskRuntimeService.executeTask(taskExecuteNormalVO));
|
return AjaxResult.success(flowTaskRuntimeService.executeTask(taskExecuteNormalVO));
|
||||||
}
|
}
|
||||||
@ -94,15 +156,120 @@ public class TeFlowController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/action")
|
@PostMapping("/action")
|
||||||
@ApiOperation("单个节点执行")
|
@ApiOperation(value = "单个节点执行",
|
||||||
public AjaxResult actionExecute(@RequestBody FlowActionRequestVO flowActionRequestVO) {
|
notes = "巡检仪表节点action=INSPECTION_METER_RECOGNIZE,payload使用InspectionMeterRecognizeConfigVO;"
|
||||||
|
+ "人工判断节点action=INSPECTION_MANUAL_REVIEW_CREATE,payload使用InspectionManualReviewConfigVO。"
|
||||||
|
+ "该接口用于试调节点,不会生成正式巡检任务结果")
|
||||||
|
public AjaxResult actionExecute(
|
||||||
|
@io.swagger.annotations.ApiParam(value = "单节点动作和参数", required = true)
|
||||||
|
@RequestBody FlowActionRequestVO flowActionRequestVO) {
|
||||||
return AjaxResult.ok(flowActionExecutorService.actionExecute(flowActionRequestVO));
|
return AjaxResult.ok(flowActionExecutorService.actionExecute(flowActionRequestVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用商道智能体平台。
|
||||||
|
*
|
||||||
|
* <p>前端只需要传入 text。后端固定 action、apiKey 和 TTS 参数。
|
||||||
|
* 调用会放入可取消任务中,前端可以通过 /flow/llm/stop 停止当前调用并停止 TTS。</p>
|
||||||
|
*/
|
||||||
|
@GetMapping("/llm/query")
|
||||||
|
@ApiOperation("调用商道智能体")
|
||||||
|
public AjaxResult queryAiAgent(String text) {
|
||||||
|
if (text == null || text.trim().isEmpty()) {
|
||||||
|
return AjaxResult.error("text不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
stopCurrentAiAgentFuture(true);
|
||||||
|
|
||||||
|
JSONObject params = new JSONObject();
|
||||||
|
params.put("url", TTS_PLAY_URL);
|
||||||
|
params.put("voice", "x4_yezi");
|
||||||
|
params.put("speed", 45);
|
||||||
|
params.put("volume", 100);
|
||||||
|
|
||||||
|
Future<JSONObject> future = aiAgentExecutor.submit(() -> llmAiAgentPlatformService.query(
|
||||||
|
null,
|
||||||
|
text.trim(),
|
||||||
|
AI_AGENT_API_KEY,
|
||||||
|
true,
|
||||||
|
params
|
||||||
|
));
|
||||||
|
currentAiAgentFuture = future;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return AjaxResult.ok(future.get());
|
||||||
|
} catch (CancellationException e) {
|
||||||
|
return AjaxResult.error("智能体调用已停止");
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
future.cancel(true);
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return AjaxResult.error("智能体调用被中断");
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
Throwable cause = e.getCause() == null ? e : e.getCause();
|
||||||
|
return AjaxResult.error("智能体调用失败:" + cause.getMessage());
|
||||||
|
} finally {
|
||||||
|
if (currentAiAgentFuture == future) {
|
||||||
|
currentAiAgentFuture = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止当前智能体调用,并通知 TTS 服务停止播放。
|
||||||
|
*
|
||||||
|
* <p>停止分两步:先取消当前 query 任务,触发底层 SSE 等待线程中断;
|
||||||
|
* 再调用本地 TTS stop 接口,停止已经进入播放队列的音频。</p>
|
||||||
|
*/
|
||||||
|
@PostMapping("/llm/stop")
|
||||||
|
@ApiOperation("停止商道智能体和TTS")
|
||||||
|
public AjaxResult stopAiAgent() {
|
||||||
|
stopCurrentAiAgentFuture(false);
|
||||||
|
// String ttsStopResult = stopTts();
|
||||||
|
return AjaxResult.ok("ok");
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/testrun")
|
@GetMapping("/testrun")
|
||||||
@ApiOperation("测试接口")
|
@ApiOperation("测试接口")
|
||||||
public AjaxResult testrun(@RequestParam("imageUrl") String imageUrl,
|
public AjaxResult testrun(@RequestParam("imageUrl") String imageUrl,
|
||||||
@RequestParam("iconUrl") String iconUrl) {
|
@RequestParam("iconUrl") String iconUrl) {
|
||||||
return AjaxResult.ok(tiTouchOperateService.test(imageUrl,iconUrl));
|
return AjaxResult.ok(tiTouchOperateService.test(imageUrl, iconUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消当前智能体任务。
|
||||||
|
*
|
||||||
|
* @param stopTts 是否同时停止 TTS 播放
|
||||||
|
*/
|
||||||
|
private void stopCurrentAiAgentFuture(boolean stopTts) {
|
||||||
|
Future<JSONObject> future = currentAiAgentFuture;
|
||||||
|
if (future != null && !future.isDone()) {
|
||||||
|
future.cancel(true);
|
||||||
|
}
|
||||||
|
currentAiAgentFuture = null;
|
||||||
|
if (stopTts) {
|
||||||
|
stopTts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用本地 TTS 停止接口。
|
||||||
|
*/
|
||||||
|
private String stopTts() {
|
||||||
|
try (HttpResponse response = HttpRequest.post(TTS_STOP_URL)
|
||||||
|
.timeout(3000)
|
||||||
|
.execute()) {
|
||||||
|
return response.body();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "调用TTS停止接口失败:" + e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring 容器关闭时释放智能体执行线程。
|
||||||
|
*/
|
||||||
|
@PreDestroy
|
||||||
|
public void destroy() {
|
||||||
|
stopCurrentAiAgentFuture(true);
|
||||||
|
aiAgentExecutor.shutdownNow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,14 +1,22 @@
|
|||||||
package com.cmvr.web.controller.test;
|
package com.cmvr.web.controller.test;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.cmvr.common.core.controller.BaseController;
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
import com.cmvr.common.core.domain.AjaxResult;
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.test.flow.control.FlowControlService;
|
||||||
|
import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService;
|
||||||
|
import com.cmvr.test.flow.runtime.operator.edge.ti.TiTouchOperateService;
|
||||||
import com.cmvr.test.model.vo.FlowiseActionRequestVO;
|
import com.cmvr.test.model.vo.FlowiseActionRequestVO;
|
||||||
import com.cmvr.test.model.vo.FlowiseChatRequestVO;
|
import com.cmvr.test.model.vo.FlowiseChatRequestVO;
|
||||||
import com.cmvr.test.model.vo.FlowiseStartRequestVO;
|
import com.cmvr.test.model.vo.FlowiseStartRequestVO;
|
||||||
|
import com.cmvr.test.model.vo.TeTaskExecuteNormalVO;
|
||||||
|
import com.cmvr.test.service.FlowActionExecutorService;
|
||||||
import com.cmvr.test.service.FlowiseActionService;
|
import com.cmvr.test.service.FlowiseActionService;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -16,6 +24,9 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Api(tags = "测试--flowise服务")
|
@Api(tags = "测试--flowise服务")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/flowise")
|
@RequestMapping("/flowise")
|
||||||
@ -23,11 +34,37 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
public class TeFlowiseController extends BaseController {
|
public class TeFlowiseController extends BaseController {
|
||||||
|
|
||||||
private final FlowiseActionService flowiseActionService;
|
private final FlowiseActionService flowiseActionService;
|
||||||
|
private final FlowTaskRuntimeService flowTaskRuntimeService;
|
||||||
|
private final FlowControlService flowControlService;
|
||||||
|
private final FlowActionExecutorService flowActionExecutorService;
|
||||||
|
private final TiTouchOperateService tiTouchOperateService;
|
||||||
|
private final List<String> taskInstIdList = new ArrayList<>();
|
||||||
|
|
||||||
@ApiOperation("调用flowise")
|
@ApiOperation("调用flowise")
|
||||||
@PostMapping("/start")
|
@PostMapping("/start")
|
||||||
public AjaxResult start(@RequestBody FlowiseStartRequestVO request) {
|
public AjaxResult start(@RequestBody FlowiseStartRequestVO request) {
|
||||||
return AjaxResult.ok(flowiseActionService.start(request));
|
JSONObject runParams = new JSONObject();
|
||||||
|
|
||||||
|
JSONObject runParams1 = new JSONObject();
|
||||||
|
runParams1
|
||||||
|
.put("test", request.getQuestion());
|
||||||
|
runParams.put("5bb26d52e1861c6936f3c3149eaf17e8", runParams1);
|
||||||
|
TeTaskExecuteNormalVO taskExecuteNormalVO = TeTaskExecuteNormalVO.builder()
|
||||||
|
.taskId("b6ab5ffff783d9b25d0dc34f13be222d")
|
||||||
|
.terminalId("4ed1246c465b97975f96c9ef8371a3bd")
|
||||||
|
.runParams(JSONObject.from(runParams)).build();
|
||||||
|
if (!taskInstIdList.isEmpty()) {
|
||||||
|
try {
|
||||||
|
taskInstIdList.forEach(flowControlService::stop);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 忽略
|
||||||
|
}
|
||||||
|
taskInstIdList.clear();
|
||||||
|
}
|
||||||
|
String insId = flowTaskRuntimeService.executeTask(taskExecuteNormalVO);
|
||||||
|
taskInstIdList.add(insId);
|
||||||
|
return AjaxResult.success();
|
||||||
|
// return AjaxResult.ok(flowiseActionService.start(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("根据chatId查询执行结果")
|
@ApiOperation("根据chatId查询执行结果")
|
||||||
@ -39,7 +76,17 @@ public class TeFlowiseController extends BaseController {
|
|||||||
@ApiOperation("终止flowise")
|
@ApiOperation("终止flowise")
|
||||||
@GetMapping("/abort")
|
@GetMapping("/abort")
|
||||||
public AjaxResult abort() {
|
public AjaxResult abort() {
|
||||||
return AjaxResult.ok(flowiseActionService.abort());
|
if (!taskInstIdList.isEmpty()) {
|
||||||
|
try {
|
||||||
|
taskInstIdList.forEach(flowControlService::stop);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 忽略
|
||||||
|
}
|
||||||
|
taskInstIdList.clear();
|
||||||
|
}
|
||||||
|
logger.info("取消工作流");
|
||||||
|
return AjaxResult.success();
|
||||||
|
// return AjaxResult.ok(flowiseActionService.abort());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("执行指令")
|
@ApiOperation("执行指令")
|
||||||
|
|||||||
@ -0,0 +1,214 @@
|
|||||||
|
package com.cmvr.web.controller.tts;
|
||||||
|
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.tts.domain.CorpusCategory;
|
||||||
|
import com.cmvr.tts.domain.CorpusInfo;
|
||||||
|
import com.cmvr.tts.service.ICorpusInfoService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车载语料数据Controller
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/tts/corpus")
|
||||||
|
@Api(tags = "智能座舱-车载语料管理")
|
||||||
|
public class CorpusInfoController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ICorpusInfoService corpusInfoService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询语料列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询语料列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(CorpusInfo corpus) {
|
||||||
|
startPage();
|
||||||
|
return corpusInfoService.selectCorpusList(corpus);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取语料详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取语料详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||||
|
return success(corpusInfoService.selectCorpusById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增语料
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增语料")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:add')")
|
||||||
|
@Log(title = "车载语料", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody CorpusInfo corpus) {
|
||||||
|
return toAjax(corpusInfoService.insertCorpus(corpus));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改语料
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改语料")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:edit')")
|
||||||
|
@Log(title = "车载语料", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody CorpusInfo corpus) {
|
||||||
|
return toAjax(corpusInfoService.updateCorpus(corpus));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除语料
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除语料")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:remove')")
|
||||||
|
@Log(title = "车载语料", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids) {
|
||||||
|
return toAjax(corpusInfoService.deleteCorpusByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取音频流
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取音频流")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/audio/{id}")
|
||||||
|
public void getAudio(@PathVariable String id, HttpServletResponse response) {
|
||||||
|
corpusInfoService.getAudioStream(id, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传语料音频
|
||||||
|
*/
|
||||||
|
@ApiOperation("上传语料音频")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:edit')")
|
||||||
|
@Log(title = "车载语料", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/audio/upload/{id}")
|
||||||
|
public AjaxResult uploadAudio(@PathVariable String id, @RequestParam("file") MultipartFile file) {
|
||||||
|
String path = corpusInfoService.uploadCorpusAudio(id, file);
|
||||||
|
return success(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量导入语料
|
||||||
|
*/
|
||||||
|
@ApiOperation("批量导入语料")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:import')")
|
||||||
|
@Log(title = "车载语料", businessType = BusinessType.IMPORT)
|
||||||
|
@PostMapping("/import")
|
||||||
|
public AjaxResult importData(@RequestParam("file") MultipartFile file) {
|
||||||
|
Map<String, Object> result = corpusInfoService.importCorpus(file);
|
||||||
|
return success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询看板统计数据
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询看板统计数据")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/dashboard/stats")
|
||||||
|
public AjaxResult getDashboardStats() {
|
||||||
|
return success(corpusInfoService.getDashboardStats());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按语种统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按语种统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/stats/language")
|
||||||
|
public AjaxResult getStatsByLanguage() {
|
||||||
|
return success(corpusInfoService.getStatsByLanguage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按方言统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按方言统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/stats/dialect")
|
||||||
|
public AjaxResult getStatsByDialect() {
|
||||||
|
return success(corpusInfoService.getStatsByDialect());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按情绪统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按情绪统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/stats/emotion")
|
||||||
|
public AjaxResult getStatsByEmotion() {
|
||||||
|
return success(corpusInfoService.getStatsByEmotion());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按分类统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按分类统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/stats/category")
|
||||||
|
public AjaxResult getStatsByCategory() {
|
||||||
|
return success(corpusInfoService.getStatsByCategory());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询分类树
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询分类树")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/category/tree")
|
||||||
|
public AjaxResult getCategoryTree() {
|
||||||
|
return success(corpusInfoService.getCategoryTree());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增分类
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增分类")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:add')")
|
||||||
|
@Log(title = "语料分类", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/category")
|
||||||
|
public AjaxResult addCategory(@RequestBody CorpusCategory category) {
|
||||||
|
return toAjax(corpusInfoService.insertCategory(category));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改分类
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改分类")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:edit')")
|
||||||
|
@Log(title = "语料分类", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/category")
|
||||||
|
public AjaxResult editCategory(@RequestBody CorpusCategory category) {
|
||||||
|
return toAjax(corpusInfoService.updateCategory(category));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除分类
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除分类")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:remove')")
|
||||||
|
@Log(title = "语料分类", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/category/{id}")
|
||||||
|
public AjaxResult removeCategory(@PathVariable String id) {
|
||||||
|
return toAjax(corpusInfoService.deleteCategoryById(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,253 @@
|
|||||||
|
package com.cmvr.web.controller.tts;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.llm.service.LLMAiAgentPlatformService;
|
||||||
|
import com.cmvr.tts.domain.TtsSynthesizeTask;
|
||||||
|
import com.cmvr.tts.domain.vo.LlmQueryVo;
|
||||||
|
import com.cmvr.tts.service.ITtsSynthesizeTaskService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTS合成任务Controller
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/tts/task")
|
||||||
|
@Api(tags = "智能座舱-TTS合成任务管理")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class TtsSynthesizeTaskController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ITtsSynthesizeTaskService ttsTaskService;
|
||||||
|
|
||||||
|
private final LLMAiAgentPlatformService llmAiAgentPlatformService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询TTS合成任务列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询TTS合成任务列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(TtsSynthesizeTask task) {
|
||||||
|
startPage();
|
||||||
|
return ttsTaskService.selectTtsTaskList(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取TTS合成任务详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取TTS合成任务详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||||
|
return success(ttsTaskService.selectTtsTaskById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增TTS合成任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增TTS合成任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:add')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody TtsSynthesizeTask task) {
|
||||||
|
return success(ttsTaskService.insertTtsTask(task));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增TTS合成任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("批量新增TTS合成任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:add')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/batch")
|
||||||
|
public AjaxResult batchAdd(@RequestBody List<TtsSynthesizeTask> tasks) {
|
||||||
|
return toAjax(ttsTaskService.batchInsertTtsTask(tasks));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改TTS合成任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改TTS合成任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:edit')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody TtsSynthesizeTask task) {
|
||||||
|
return toAjax(ttsTaskService.updateTtsTask(task));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除TTS合成任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除TTS合成任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:remove')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids) {
|
||||||
|
return toAjax(ttsTaskService.deleteTtsTaskByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重生成TTS任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("重生成TTS任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:edit')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/regenerate/{id}")
|
||||||
|
public AjaxResult regenerate(@PathVariable String id) {
|
||||||
|
return toAjax(ttsTaskService.regenerateTask(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取音频文件流
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取音频文件流")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/audio/{id}")
|
||||||
|
public void getAudio(@PathVariable String id, HttpServletResponse response) {
|
||||||
|
ttsTaskService.getAudioStream(id, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询看板统计数据
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询看板统计数据")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/dashboard/stats")
|
||||||
|
public AjaxResult getDashboardStats() {
|
||||||
|
return success(ttsTaskService.getDashboardStats());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按语种统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按语种统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/stats/language")
|
||||||
|
public AjaxResult getStatsByLanguage() {
|
||||||
|
return success(ttsTaskService.getStatsByLanguage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按音色统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按音色统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/stats/voice")
|
||||||
|
public AjaxResult getStatsByVoice() {
|
||||||
|
return success(ttsTaskService.getStatsByVoice());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按情绪统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按情绪统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/stats/emotion")
|
||||||
|
public AjaxResult getStatsByEmotion() {
|
||||||
|
return success(ttsTaskService.getStatsByEmotion());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 近7日趋势
|
||||||
|
*/
|
||||||
|
@ApiOperation("近7日趋势")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/stats/trend")
|
||||||
|
public AjaxResult getLast7DaysTrend() {
|
||||||
|
return success(ttsTaskService.getLast7DaysTrend());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本泛化
|
||||||
|
*/
|
||||||
|
@ApiOperation("文本泛化")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@PostMapping("/llm/query")
|
||||||
|
public AjaxResult llmQuery(@RequestBody LlmQueryVo request) {
|
||||||
|
// 闲聊key d9672ql4shh4136opsfg
|
||||||
|
// 泛化key d966pq54shh4nveh8d20
|
||||||
|
JSONObject result = llmAiAgentPlatformService.query(
|
||||||
|
null,
|
||||||
|
request.getLanguage() + "," + request.getCount() + "," + request.getText(),
|
||||||
|
"d96ammd4shh4nvehb6mg",
|
||||||
|
false,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
// 解析LLM返回的结果,提取JSON数组
|
||||||
|
String resultStr = result.getString("result");
|
||||||
|
if (resultStr != null && !resultStr.isEmpty()) {
|
||||||
|
// 尝试多种格式解析
|
||||||
|
JSONArray jsonArray = parseJsonArray(resultStr);
|
||||||
|
return success(jsonArray);
|
||||||
|
}
|
||||||
|
return success(new JSONArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析JSON数组,兼容多种格式
|
||||||
|
*/
|
||||||
|
private JSONArray parseJsonArray(String text) {
|
||||||
|
if (text == null || text.isEmpty()) {
|
||||||
|
return new JSONArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 直接尝试解析为JSON数组
|
||||||
|
try {
|
||||||
|
return JSONArray.parseArray(text);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 继续尝试其他格式
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 2. 移除markdown代码块标记
|
||||||
|
String cleaned = text.replace("```json", "").replace("```", "").trim();
|
||||||
|
try {
|
||||||
|
return JSONArray.parseArray(cleaned);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 继续尝试其他格式
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 尝试从文本中提取JSON数组(匹配 [...] 格式)
|
||||||
|
int startIdx = text.indexOf("[");
|
||||||
|
int endIdx = text.lastIndexOf("]");
|
||||||
|
if (startIdx != -1 && endIdx != -1 && endIdx > startIdx) {
|
||||||
|
String jsonStr = text.substring(startIdx, endIdx + 1);
|
||||||
|
try {
|
||||||
|
return JSONArray.parseArray(jsonStr);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 继续尝试其他格式
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 如果都失败,返回包含原始文本的数组
|
||||||
|
return new JSONArray().fluentAdd(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存任务到语料库
|
||||||
|
*/
|
||||||
|
@ApiOperation("保存任务到语料库")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:edit')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/Nsave-to-corpus/{taskId}/{categoryId}")
|
||||||
|
public AjaxResult saveToCorpus(@PathVariable String taskId, @PathVariable String categoryId) {
|
||||||
|
return toAjax(ttsTaskService.saveToCorpus(taskId, categoryId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,11 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import com.cmvr.common.config.CmvrIotConfig;
|
import com.cmvr.common.config.CmvrIotConfig;
|
||||||
|
import com.cmvr.test.model.vo.inspection.InspectionAlarmRuleVO;
|
||||||
|
import com.cmvr.test.model.vo.inspection.InspectionManualReviewConfigVO;
|
||||||
|
import com.cmvr.test.model.vo.inspection.InspectionMediaVO;
|
||||||
|
import com.cmvr.test.model.vo.inspection.InspectionMeterRecognizeConfigVO;
|
||||||
|
import com.fasterxml.classmate.TypeResolver;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import io.swagger.models.auth.In;
|
import io.swagger.models.auth.In;
|
||||||
import springfox.documentation.builders.ApiInfoBuilder;
|
import springfox.documentation.builders.ApiInfoBuilder;
|
||||||
@ -34,6 +39,10 @@ public class SwaggerConfig
|
|||||||
@Autowired
|
@Autowired
|
||||||
private CmvrIotConfig cmvrIotConfig;
|
private CmvrIotConfig cmvrIotConfig;
|
||||||
|
|
||||||
|
/** 用于将动态工作流payload对应的参数模型显式加入Swagger文档。 */
|
||||||
|
@Autowired
|
||||||
|
private TypeResolver typeResolver;
|
||||||
|
|
||||||
/** 是否开启swagger */
|
/** 是否开启swagger */
|
||||||
@Value("${swagger.enabled}")
|
@Value("${swagger.enabled}")
|
||||||
private boolean enabled;
|
private boolean enabled;
|
||||||
@ -62,6 +71,12 @@ public class SwaggerConfig
|
|||||||
// 扫描所有 .apis(RequestHandlerSelectors.any())
|
// 扫描所有 .apis(RequestHandlerSelectors.any())
|
||||||
.paths(PathSelectors.any())
|
.paths(PathSelectors.any())
|
||||||
.build()
|
.build()
|
||||||
|
// 工作流单节点接口使用JSONObject作为payload,需显式注册巡检节点参数模型。
|
||||||
|
.additionalModels(
|
||||||
|
typeResolver.resolve(InspectionMeterRecognizeConfigVO.class),
|
||||||
|
typeResolver.resolve(InspectionAlarmRuleVO.class),
|
||||||
|
typeResolver.resolve(InspectionManualReviewConfigVO.class),
|
||||||
|
typeResolver.resolve(InspectionMediaVO.class))
|
||||||
/* 设置安全模式,swagger可以设置访问token */
|
/* 设置安全模式,swagger可以设置访问token */
|
||||||
.securitySchemes(securitySchemes())
|
.securitySchemes(securitySchemes())
|
||||||
.securityContexts(securityContexts())
|
.securityContexts(securityContexts())
|
||||||
|
|||||||
@ -1,111 +1,111 @@
|
|||||||
server:
|
server:
|
||||||
# 服务器的HTTP端口,默认为8080
|
# 服务器的HTTP端口,默认为8080
|
||||||
port: 13080
|
port: 13080
|
||||||
# 数据源配置
|
# 数据源配置
|
||||||
spring:
|
spring:
|
||||||
datasource:
|
datasource:
|
||||||
type: com.alibaba.druid.pool.DruidDataSource
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
driverClassName: com.mysql.cj.jdbc.Driver
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
druid:
|
druid:
|
||||||
# 主库数据源
|
# 主库数据源
|
||||||
master:
|
master:
|
||||||
url: jdbc:mysql://192.168.0.100:3306/cmvr-iot-dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
url: jdbc:mysql://192.168.28.10:3306/cmvr-iot-dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
username: cmvr-iot
|
username: root
|
||||||
password: cmvr-iot123456
|
|
||||||
# 从库数据源
|
|
||||||
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: cmvr-iot
|
|
||||||
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
|
|
||||||
# 服务模块
|
|
||||||
devtools:
|
|
||||||
restart:
|
|
||||||
# 热部署开关
|
|
||||||
enabled: true
|
|
||||||
# redis 配置
|
|
||||||
redis:
|
|
||||||
# 地址
|
|
||||||
host: 192.168.0.100
|
|
||||||
# 端口,默认为6379
|
|
||||||
port: 6379
|
|
||||||
# 数据库索引
|
|
||||||
database: 0
|
|
||||||
# 密码
|
|
||||||
password: cmvr2468
|
password: cmvr2468
|
||||||
# 连接超时时间
|
# 从库数据源
|
||||||
timeout: 10s
|
slave:
|
||||||
lettuce:
|
# 从数据源开关/默认关闭
|
||||||
pool:
|
enabled: false
|
||||||
# 连接池:中的最小空闲连接
|
url:
|
||||||
min-idle: 0
|
username:
|
||||||
# 连接池中的最大空闲连接
|
password:
|
||||||
max-idle: 8
|
# 初始连接数
|
||||||
# 连接池的最大数据库连接数
|
initialSize: 5
|
||||||
max-active: 8
|
# 最小连接池数量
|
||||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
minIdle: 10
|
||||||
max-wait: -1ms
|
# 最大连接池数量
|
||||||
|
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: cmvr-iot
|
||||||
|
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
|
||||||
|
# 服务模块
|
||||||
|
devtools:
|
||||||
|
restart:
|
||||||
|
# 热部署开关
|
||||||
|
enabled: true
|
||||||
|
# redis 配置
|
||||||
|
redis:
|
||||||
|
# 地址
|
||||||
|
host: 192.168.28.10
|
||||||
|
# 端口,默认为6379
|
||||||
|
port: 6379
|
||||||
|
# 数据库索引
|
||||||
|
database: 0
|
||||||
|
# 密码
|
||||||
|
password: cmvr2468
|
||||||
|
# 连接超时时间
|
||||||
|
timeout: 10s
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
# 连接池:中的最小空闲连接
|
||||||
|
min-idle: 0
|
||||||
|
# 连接池中的最大空闲连接
|
||||||
|
max-idle: 8
|
||||||
|
# 连接池的最大数据库连接数
|
||||||
|
max-active: 8
|
||||||
|
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||||
|
max-wait: -1ms
|
||||||
|
|
||||||
# Minio配置
|
# Minio配置
|
||||||
minio:
|
minio:
|
||||||
url: http://192.168.0.100:9000
|
url: http://192.168.28.10:9000
|
||||||
accessKey: AKICMVR
|
accessKey: AKICMVR
|
||||||
secretKey: wJalrXUtnFEMI
|
secretKey: wJalrXUtnFEMI
|
||||||
bucketName: cmvr-iot
|
bucketName: cmvr-iot
|
||||||
|
|
||||||
# gRPC 客户端设置
|
# gRPC 客户端设置
|
||||||
grpc:
|
grpc:
|
||||||
client:
|
client:
|
||||||
grpc-server: # 自定义服务名
|
grpc-server: # 自定义服务名
|
||||||
address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
||||||
# address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
# address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
||||||
enableKeepAlive: true
|
enableKeepAlive: true
|
||||||
keepAliveWithoutCalls: true
|
keepAliveWithoutCalls: true
|
||||||
negotiationType: plaintext # 明文传输
|
negotiationType: plaintext # 明文传输
|
||||||
|
|
||||||
api:
|
api:
|
||||||
app-id: d0epfibvo3em6c4iul40
|
app-id: d0epfibvo3em6c4iul40
|
||||||
@ -121,8 +121,8 @@ api:
|
|||||||
app-id: d5dn5ibp9adhq1b34lig
|
app-id: d5dn5ibp9adhq1b34lig
|
||||||
app-key: d6j5bcellh49on5tasvg
|
app-key: d6j5bcellh49on5tasvg
|
||||||
TI_TOUCH_COORDINATES: # 获取触控二维坐标
|
TI_TOUCH_COORDINATES: # 获取触控二维坐标
|
||||||
app-id: d1ebtabnjkflk4gmhikg
|
app-id: d1ebtabnjkflk4gmhikg
|
||||||
app-key: d5thge2cktmipk78h82g
|
app-key: d5thge2cktmipk78h82g
|
||||||
evaluation: http://192.168.0.8:8000/analyze
|
evaluation: http://192.168.0.8:8000/analyze
|
||||||
current-page: http://192.168.0.222:5000/search_similar
|
current-page: http://192.168.0.222:5000/search_similar
|
||||||
|
|
||||||
@ -132,3 +132,8 @@ flowise:
|
|||||||
abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/f99329e9-b33d-437d-90ed-69eaa8a05418/
|
abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/f99329e9-b33d-437d-90ed-69eaa8a05418/
|
||||||
query: http://192.168.0.108:3000/api/v1/executions/
|
query: http://192.168.0.108:3000/api/v1/executions/
|
||||||
api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg
|
api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg
|
||||||
|
|
||||||
|
# TTS外部接口配置
|
||||||
|
tts:
|
||||||
|
external-api:
|
||||||
|
url: http://192.168.0.102:9003/generate_advanced_audio
|
||||||
134
cmvr-iot-admin/src/main/resources/application-devbak.yml
Normal file
134
cmvr-iot-admin/src/main/resources/application-devbak.yml
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
server:
|
||||||
|
# 服务器的HTTP端口,默认为8080
|
||||||
|
port: 13080
|
||||||
|
# 数据源配置
|
||||||
|
spring:
|
||||||
|
datasource:
|
||||||
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
|
druid:
|
||||||
|
# 主库数据源
|
||||||
|
master:
|
||||||
|
url: jdbc:mysql://192.168.0.100:3306/cmvr-iot-dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
|
username: cmvr-iot
|
||||||
|
password: cmvr-iot123456
|
||||||
|
# 从库数据源
|
||||||
|
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: cmvr-iot
|
||||||
|
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
|
||||||
|
# 服务模块
|
||||||
|
devtools:
|
||||||
|
restart:
|
||||||
|
# 热部署开关
|
||||||
|
enabled: true
|
||||||
|
# redis 配置
|
||||||
|
redis:
|
||||||
|
# 地址
|
||||||
|
host: 192.168.0.100
|
||||||
|
# 端口,默认为6379
|
||||||
|
port: 6379
|
||||||
|
# 数据库索引
|
||||||
|
database: 0
|
||||||
|
# 密码
|
||||||
|
password: cmvr2468
|
||||||
|
# 连接超时时间
|
||||||
|
timeout: 10s
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
# 连接池:中的最小空闲连接
|
||||||
|
min-idle: 0
|
||||||
|
# 连接池中的最大空闲连接
|
||||||
|
max-idle: 8
|
||||||
|
# 连接池的最大数据库连接数
|
||||||
|
max-active: 8
|
||||||
|
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||||
|
max-wait: -1ms
|
||||||
|
|
||||||
|
# Minio配置
|
||||||
|
minio:
|
||||||
|
url: http://192.168.0.100:9000
|
||||||
|
accessKey: AKICMVR
|
||||||
|
secretKey: wJalrXUtnFEMI
|
||||||
|
bucketName: cmvr-iot
|
||||||
|
|
||||||
|
# gRPC 客户端设置
|
||||||
|
grpc:
|
||||||
|
client:
|
||||||
|
grpc-server: # 自定义服务名
|
||||||
|
address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
||||||
|
# address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
||||||
|
enableKeepAlive: true
|
||||||
|
keepAliveWithoutCalls: true
|
||||||
|
negotiationType: plaintext # 明文传输
|
||||||
|
|
||||||
|
api:
|
||||||
|
app-id: d0epfibvo3em6c4iul40
|
||||||
|
app-key: d0eqt1kqek3vg7g4ofi0
|
||||||
|
work-flow-url: https://aiagentplatform.cmft.com/api/proxy/api/v1/run_app_workflow
|
||||||
|
query-result-url: https://aiagentplatform.cmft.com/api/proxy/api/v1/query_run_app_process
|
||||||
|
bge-vl: http://192.168.1.8:5000/search_similar
|
||||||
|
generate_advanced_audio: http://192.168.0.102:9003/generate_advanced_audio
|
||||||
|
# 智能体应用id和秘钥
|
||||||
|
# ActionEnum 的枚举作为 key
|
||||||
|
agents:
|
||||||
|
INTENT_RECOGNITION: # 意图识别
|
||||||
|
app-id: d5dn5ibp9adhq1b34lig
|
||||||
|
app-key: d6j5bcellh49on5tasvg
|
||||||
|
TI_TOUCH_COORDINATES: # 获取触控二维坐标
|
||||||
|
app-id: d1ebtabnjkflk4gmhikg
|
||||||
|
app-key: d5thge2cktmipk78h82g
|
||||||
|
evaluation: http://192.168.0.8:8000/analyze
|
||||||
|
current-page: http://192.168.0.222:5000/search_similar
|
||||||
|
|
||||||
|
flowise:
|
||||||
|
tts: 192.168.0.222:8080/tts/
|
||||||
|
start: http://192.168.0.108:3000/api/v1/prediction/f99329e9-b33d-437d-90ed-69eaa8a05418
|
||||||
|
abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/f99329e9-b33d-437d-90ed-69eaa8a05418/
|
||||||
|
query: http://192.168.0.108:3000/api/v1/executions/
|
||||||
|
api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg
|
||||||
@ -9,9 +9,9 @@ spring:
|
|||||||
druid:
|
druid:
|
||||||
# 主库数据源
|
# 主库数据源
|
||||||
master:
|
master:
|
||||||
url: jdbc:mysql://mysql57:3306/cmvr-iot-dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
url: jdbc:mysql://192.168.28.10:3306/cmvr-iot-dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
username: cmvr-iot
|
username: root
|
||||||
password: cmvr-iot123456
|
password: cmvr2468
|
||||||
# 从库数据源
|
# 从库数据源
|
||||||
slave:
|
slave:
|
||||||
# 从数据源开关/默认关闭
|
# 从数据源开关/默认关闭
|
||||||
@ -70,7 +70,7 @@ spring:
|
|||||||
# redis 配置
|
# redis 配置
|
||||||
redis:
|
redis:
|
||||||
# 地址
|
# 地址
|
||||||
host: redis
|
host: 192.168.28.10
|
||||||
# 端口,默认为6379
|
# 端口,默认为6379
|
||||||
port: 6379
|
port: 6379
|
||||||
# 数据库索引
|
# 数据库索引
|
||||||
@ -92,7 +92,7 @@ spring:
|
|||||||
|
|
||||||
# Minio配置
|
# Minio配置
|
||||||
minio:
|
minio:
|
||||||
url: http://mini:9000
|
url: http://192.168.28.10:9000
|
||||||
accessKey: AKICMVR
|
accessKey: AKICMVR
|
||||||
secretKey: wJalrXUtnFEMI
|
secretKey: wJalrXUtnFEMI
|
||||||
bucketName: cmvr-iot
|
bucketName: cmvr-iot
|
||||||
@ -118,8 +118,8 @@ api:
|
|||||||
# ActionEnum 的枚举作为 key
|
# ActionEnum 的枚举作为 key
|
||||||
agents:
|
agents:
|
||||||
INTENT_RECOGNITION: # 意图识别
|
INTENT_RECOGNITION: # 意图识别
|
||||||
app-id: d3c98sp0gdon0fcf6l00
|
app-id: d5dn5ibp9adhq1b34lig
|
||||||
app-key: d3c98vp0gdon0fcf6n20
|
app-key: d6j5bcellh49on5tasvg
|
||||||
TI_TOUCH_COORDINATES: # 获取触控二维坐标
|
TI_TOUCH_COORDINATES: # 获取触控二维坐标
|
||||||
app-id: d1ebtabnjkflk4gmhikg
|
app-id: d1ebtabnjkflk4gmhikg
|
||||||
app-key: d5thge2cktmipk78h82g
|
app-key: d5thge2cktmipk78h82g
|
||||||
@ -128,7 +128,7 @@ api:
|
|||||||
|
|
||||||
flowise:
|
flowise:
|
||||||
tts: 192.168.0.222:8080/tts/
|
tts: 192.168.0.222:8080/tts/
|
||||||
start: http://192.168.0.108:3000/api/v1/prediction/86f01c9d-aaf4-495e-9530-d02e3172c807
|
start: http://192.168.0.108:3000/api/v1/prediction/f99329e9-b33d-437d-90ed-69eaa8a05418
|
||||||
abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/86f01c9d-aaf4-495e-9530-d02e3172c807/
|
abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/f99329e9-b33d-437d-90ed-69eaa8a05418/
|
||||||
query: http://192.168.0.108:3000/api/v1/executions/
|
query: http://192.168.0.108:3000/api/v1/executions/
|
||||||
api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg
|
api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg
|
||||||
134
cmvr-iot-admin/src/main/resources/application-prodbak.yml
Normal file
134
cmvr-iot-admin/src/main/resources/application-prodbak.yml
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
server:
|
||||||
|
# 服务器的HTTP端口,默认为8080
|
||||||
|
port: 13080
|
||||||
|
# 数据源配置
|
||||||
|
spring:
|
||||||
|
datasource:
|
||||||
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
|
druid:
|
||||||
|
# 主库数据源
|
||||||
|
master:
|
||||||
|
url: jdbc:mysql://mysql57:3306/cmvr-iot-dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
|
username: cmvr-iot
|
||||||
|
password: cmvr-iot123456
|
||||||
|
# 从库数据源
|
||||||
|
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: cmvr-iot
|
||||||
|
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
|
||||||
|
# 服务模块
|
||||||
|
devtools:
|
||||||
|
restart:
|
||||||
|
# 热部署开关
|
||||||
|
enabled: true
|
||||||
|
# redis 配置
|
||||||
|
redis:
|
||||||
|
# 地址
|
||||||
|
host: redis
|
||||||
|
# 端口,默认为6379
|
||||||
|
port: 6379
|
||||||
|
# 数据库索引
|
||||||
|
database: 0
|
||||||
|
# 密码
|
||||||
|
password: cmvr2468
|
||||||
|
# 连接超时时间
|
||||||
|
timeout: 10s
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
# 连接池:中的最小空闲连接
|
||||||
|
min-idle: 0
|
||||||
|
# 连接池中的最大空闲连接
|
||||||
|
max-idle: 8
|
||||||
|
# 连接池的最大数据库连接数
|
||||||
|
max-active: 8
|
||||||
|
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||||
|
max-wait: -1ms
|
||||||
|
|
||||||
|
# Minio配置
|
||||||
|
minio:
|
||||||
|
url: http://minio:9000
|
||||||
|
accessKey: AKICMVR
|
||||||
|
secretKey: wJalrXUtnFEMI
|
||||||
|
bucketName: cmvr-iot
|
||||||
|
|
||||||
|
# gRPC 客户端设置
|
||||||
|
grpc:
|
||||||
|
client:
|
||||||
|
grpc-server: # 自定义服务名
|
||||||
|
address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
||||||
|
# address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
||||||
|
enableKeepAlive: true
|
||||||
|
keepAliveWithoutCalls: true
|
||||||
|
negotiationType: plaintext # 明文传输
|
||||||
|
|
||||||
|
api:
|
||||||
|
app-id: d0epfibvo3em6c4iul40
|
||||||
|
app-key: d0eqt1kqek3vg7g4ofi0
|
||||||
|
work-flow-url: https://aiagentplatform.cmft.com/api/proxy/api/v1/run_app_workflow
|
||||||
|
query-result-url: https://aiagentplatform.cmft.com/api/proxy/api/v1/query_run_app_process
|
||||||
|
bge-vl: http://192.168.1.8:5000/search_similar
|
||||||
|
generate_advanced_audio: http://192.168.0.102:9003/generate_advanced_audio
|
||||||
|
# 智能体应用id和秘钥
|
||||||
|
# ActionEnum 的枚举作为 key
|
||||||
|
agents:
|
||||||
|
INTENT_RECOGNITION: # 意图识别
|
||||||
|
app-id: d5dn5ibp9adhq1b34lig
|
||||||
|
app-key: d6j5bcellh49on5tasvg
|
||||||
|
TI_TOUCH_COORDINATES: # 获取触控二维坐标
|
||||||
|
app-id: d1ebtabnjkflk4gmhikg
|
||||||
|
app-key: d5thge2cktmipk78h82g
|
||||||
|
evaluation: http://192.168.0.8:8000/analyze
|
||||||
|
current-page: http://192.168.0.222:5000/search_similar
|
||||||
|
|
||||||
|
flowise:
|
||||||
|
tts: 192.168.0.222:8080/tts/
|
||||||
|
start: http://192.168.0.108:3000/api/v1/prediction/86f01c9d-aaf4-495e-9530-d02e3172c807
|
||||||
|
abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/86f01c9d-aaf4-495e-9530-d02e3172c807/
|
||||||
|
query: http://192.168.0.108:3000/api/v1/executions/
|
||||||
|
api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg
|
||||||
@ -1,81 +1,134 @@
|
|||||||
server:
|
server:
|
||||||
# 服务器的HTTP端口,默认为8080
|
# 服务器的HTTP端口,默认为8080
|
||||||
port: 13080
|
port: 13080
|
||||||
# 数据源配置
|
# 数据源配置
|
||||||
spring:
|
spring:
|
||||||
datasource:
|
datasource:
|
||||||
type: com.alibaba.druid.pool.DruidDataSource
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
driverClassName: com.mysql.cj.jdbc.Driver
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
druid:
|
druid:
|
||||||
# 主库数据源
|
# 主库数据源
|
||||||
master:
|
master:
|
||||||
url: jdbc:mysql://10.148.20.35:3306/cmvr-iot-dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
url: jdbc:mysql://192.168.28.10:3306/cmvr-iot-dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
username: cmvr-iot
|
username: root
|
||||||
password: cmvr-iot123456
|
password: cmvr2468
|
||||||
# 从库数据源
|
# 从库数据源
|
||||||
slave:
|
slave:
|
||||||
# 从数据源开关/默认关闭
|
# 从数据源开关/默认关闭
|
||||||
enabled: false
|
enabled: false
|
||||||
url:
|
url:
|
||||||
username:
|
username:
|
||||||
password:
|
password:
|
||||||
# 初始连接数
|
# 初始连接数
|
||||||
initialSize: 5
|
initialSize: 5
|
||||||
# 最小连接池数量
|
# 最小连接池数量
|
||||||
minIdle: 10
|
minIdle: 10
|
||||||
# 最大连接池数量
|
# 最大连接池数量
|
||||||
maxActive: 20
|
maxActive: 20
|
||||||
# 配置获取连接等待超时的时间
|
# 配置获取连接等待超时的时间
|
||||||
maxWait: 60000
|
maxWait: 60000
|
||||||
# 配置连接超时时间
|
# 配置连接超时时间
|
||||||
connectTimeout: 30000
|
connectTimeout: 30000
|
||||||
# 配置网络超时时间
|
# 配置网络超时时间
|
||||||
socketTimeout: 60000
|
socketTimeout: 60000
|
||||||
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||||
timeBetweenEvictionRunsMillis: 60000
|
timeBetweenEvictionRunsMillis: 60000
|
||||||
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||||
minEvictableIdleTimeMillis: 300000
|
minEvictableIdleTimeMillis: 300000
|
||||||
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
||||||
maxEvictableIdleTimeMillis: 900000
|
maxEvictableIdleTimeMillis: 900000
|
||||||
# 配置检测连接是否有效
|
# 配置检测连接是否有效
|
||||||
validationQuery: SELECT 1 FROM DUAL
|
validationQuery: SELECT 1 FROM DUAL
|
||||||
testWhileIdle: true
|
testWhileIdle: true
|
||||||
testOnBorrow: false
|
testOnBorrow: false
|
||||||
testOnReturn: false
|
testOnReturn: false
|
||||||
webStatFilter:
|
webStatFilter:
|
||||||
enabled: true
|
enabled: true
|
||||||
statViewServlet:
|
statViewServlet:
|
||||||
enabled: true
|
enabled: true
|
||||||
# 设置白名单,不填则允许所有访问
|
# 设置白名单,不填则允许所有访问
|
||||||
allow:
|
allow:
|
||||||
url-pattern: /druid/*
|
url-pattern: /druid/*
|
||||||
# 控制台管理用户名和密码
|
# 控制台管理用户名和密码
|
||||||
login-username: cmvr-iot
|
login-username: cmvr-iot
|
||||||
login-password: 123456
|
login-password: 123456
|
||||||
filter:
|
filter:
|
||||||
stat:
|
stat:
|
||||||
enabled: true
|
enabled: true
|
||||||
# 慢SQL记录
|
# 慢SQL记录
|
||||||
log-slow-sql: true
|
log-slow-sql: true
|
||||||
slow-sql-millis: 1000
|
slow-sql-millis: 1000
|
||||||
merge-sql: true
|
merge-sql: true
|
||||||
wall:
|
wall:
|
||||||
config:
|
config:
|
||||||
multi-statement-allow: true
|
multi-statement-allow: true
|
||||||
|
# 服务模块
|
||||||
|
devtools:
|
||||||
|
restart:
|
||||||
|
# 热部署开关
|
||||||
|
enabled: true
|
||||||
|
# redis 配置
|
||||||
|
redis:
|
||||||
|
# 地址
|
||||||
|
host: 192.168.28.10
|
||||||
|
# 端口,默认为6379
|
||||||
|
port: 6379
|
||||||
|
# 数据库索引
|
||||||
|
database: 0
|
||||||
|
# 密码
|
||||||
|
password: cmvr2468
|
||||||
|
# 连接超时时间
|
||||||
|
timeout: 10s
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
# 连接池:中的最小空闲连接
|
||||||
|
min-idle: 0
|
||||||
|
# 连接池中的最大空闲连接
|
||||||
|
max-idle: 8
|
||||||
|
# 连接池的最大数据库连接数
|
||||||
|
max-active: 8
|
||||||
|
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||||
|
max-wait: -1ms
|
||||||
|
|
||||||
# Minio配置
|
# Minio配置
|
||||||
minio:
|
minio:
|
||||||
url: http://10.148.20.35:9000
|
url: http://192.168.28.10:9000
|
||||||
accessKey: AKIBSP
|
accessKey: AKICMVR
|
||||||
secretKey: wJalrXUtnFEMI
|
secretKey: wJalrXUtnFEMI
|
||||||
bucketName: cmvr-iot
|
bucketName: cmvr-iot
|
||||||
|
|
||||||
# gRPC 客户端设置
|
# gRPC 客户端设置
|
||||||
grpc:
|
grpc:
|
||||||
client:
|
client:
|
||||||
grpc-server: # 自定义服务名
|
grpc-server: # 自定义服务名
|
||||||
address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
||||||
# address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
# address: 'static://10.148.108.100:50051' # 调用 gRPC 的地址
|
||||||
enableKeepAlive: true
|
enableKeepAlive: true
|
||||||
keepAliveWithoutCalls: true
|
keepAliveWithoutCalls: true
|
||||||
negotiationType: plaintext # 明文传输
|
negotiationType: plaintext # 明文传输
|
||||||
|
|
||||||
|
api:
|
||||||
|
app-id: d0epfibvo3em6c4iul40
|
||||||
|
app-key: d0eqt1kqek3vg7g4ofi0
|
||||||
|
work-flow-url: https://aiagentplatform.cmft.com/api/proxy/api/v1/run_app_workflow
|
||||||
|
query-result-url: https://aiagentplatform.cmft.com/api/proxy/api/v1/query_run_app_process
|
||||||
|
bge-vl: http://192.168.1.8:5000/search_similar
|
||||||
|
generate_advanced_audio: http://192.168.0.102:9003/generate_advanced_audio
|
||||||
|
# 智能体应用id和秘钥
|
||||||
|
# ActionEnum 的枚举作为 key
|
||||||
|
agents:
|
||||||
|
INTENT_RECOGNITION: # 意图识别
|
||||||
|
app-id: d5dn5ibp9adhq1b34lig
|
||||||
|
app-key: d6j5bcellh49on5tasvg
|
||||||
|
TI_TOUCH_COORDINATES: # 获取触控二维坐标
|
||||||
|
app-id: d1ebtabnjkflk4gmhikg
|
||||||
|
app-key: d5thge2cktmipk78h82g
|
||||||
|
evaluation: http://192.168.0.8:8000/analyze
|
||||||
|
current-page: http://192.168.0.222:5000/search_similar
|
||||||
|
|
||||||
|
flowise:
|
||||||
|
tts: 192.168.0.222:8080/tts/
|
||||||
|
start: http://192.168.0.108:3000/api/v1/prediction/f99329e9-b33d-437d-90ed-69eaa8a05418
|
||||||
|
abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/f99329e9-b33d-437d-90ed-69eaa8a05418/
|
||||||
|
query: http://192.168.0.108:3000/api/v1/executions/
|
||||||
|
api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg
|
||||||
@ -21,6 +21,9 @@ server:
|
|||||||
tomcat:
|
tomcat:
|
||||||
# tomcat的URI编码
|
# tomcat的URI编码
|
||||||
uri-encoding: UTF-8
|
uri-encoding: UTF-8
|
||||||
|
# PPE报警包含Base64图片,允许读取较大的JSON请求,同时限制异常请求的吞入大小
|
||||||
|
max-http-form-post-size: 20MB
|
||||||
|
max-swallow-size: 20MB
|
||||||
# 连接数满后的排队数,默认为100
|
# 连接数满后的排队数,默认为100
|
||||||
accept-count: 1000
|
accept-count: 1000
|
||||||
threads:
|
threads:
|
||||||
@ -50,7 +53,7 @@ spring:
|
|||||||
# 国际化资源文件路径
|
# 国际化资源文件路径
|
||||||
basename: i18n/messages
|
basename: i18n/messages
|
||||||
profiles:
|
profiles:
|
||||||
active: dev
|
active: test
|
||||||
# 文件上传
|
# 文件上传
|
||||||
servlet:
|
servlet:
|
||||||
multipart:
|
multipart:
|
||||||
|
|||||||
33
cmvr-iot-aima/pom.xml
Normal file
33
cmvr-iot-aima/pom.xml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?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.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot</artifactId>
|
||||||
|
<version>3.8.9</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>cmvr-iot-aima</artifactId>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
爱玛电动车测试模块
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- 通用工具-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot-common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 测试模块-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot-test</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
144
cmvr-iot-aima/src/main/java/com/cmvr/aima/domain/AimaAlarm.java
Normal file
144
cmvr-iot-aima/src/main/java/com/cmvr/aima/domain/AimaAlarm.java
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package com.cmvr.aima.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛告警实体。
|
||||||
|
* <p>
|
||||||
|
* 用于描述任务执行过程中产生的告警信息,包含任务、设备、车辆、用例、
|
||||||
|
* 告警详情以及处理结果等数据。
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("爱玛告警管理")
|
||||||
|
public class AimaAlarm extends BaseEntity
|
||||||
|
{
|
||||||
|
/** 序列化版本号。 */
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 主键ID。 */
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
@TableId(value = "id", type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/** 告警编码。 */
|
||||||
|
@Excel(name = "告警编码")
|
||||||
|
@ApiModelProperty("告警编码")
|
||||||
|
private String alarmCode;
|
||||||
|
|
||||||
|
/** 任务执行实例ID。 */
|
||||||
|
@Excel(name = "任务执行实例ID")
|
||||||
|
@ApiModelProperty("任务执行实例ID")
|
||||||
|
private String taskInstanceId;
|
||||||
|
|
||||||
|
/** 任务ID。 */
|
||||||
|
@Excel(name = "任务ID")
|
||||||
|
@ApiModelProperty("任务ID")
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
/** 任务名称。 */
|
||||||
|
@Excel(name = "任务名称")
|
||||||
|
@ApiModelProperty("任务名称")
|
||||||
|
private String taskName;
|
||||||
|
|
||||||
|
/** 手机ID。 */
|
||||||
|
@Excel(name = "手机ID")
|
||||||
|
@ApiModelProperty("手机ID")
|
||||||
|
private String phoneId;
|
||||||
|
|
||||||
|
/** 手机名称。 */
|
||||||
|
@Excel(name = "手机名称")
|
||||||
|
@ApiModelProperty("手机名称")
|
||||||
|
private String phoneName;
|
||||||
|
|
||||||
|
/** 车辆ID。 */
|
||||||
|
@Excel(name = "车辆ID")
|
||||||
|
@ApiModelProperty("车辆ID")
|
||||||
|
private String vehicleId;
|
||||||
|
|
||||||
|
/** 车辆车架号。 */
|
||||||
|
@Excel(name = "车架号")
|
||||||
|
@ApiModelProperty("车架号")
|
||||||
|
private String vin;
|
||||||
|
|
||||||
|
/** 测试用例ID。 */
|
||||||
|
@Excel(name = "测试用例ID")
|
||||||
|
@ApiModelProperty("测试用例ID")
|
||||||
|
private String testCaseId;
|
||||||
|
|
||||||
|
/** 测试用例名称。 */
|
||||||
|
@Excel(name = "用例名称")
|
||||||
|
@ApiModelProperty("用例名称")
|
||||||
|
private String caseName;
|
||||||
|
|
||||||
|
/** 告警级别:1提示,2警告,3严重。 */
|
||||||
|
@Excel(name = "告警级别")
|
||||||
|
@ApiModelProperty("告警级别(1提示 2警告 3严重)")
|
||||||
|
private String alarmLevel;
|
||||||
|
|
||||||
|
/** 告警类型:1设备异常,2测试异常,3通信异常,4性能异常。 */
|
||||||
|
@Excel(name = "告警类型")
|
||||||
|
@ApiModelProperty("告警类型(1设备异常 2测试异常 3通信异常 4性能异常)")
|
||||||
|
private String alarmType;
|
||||||
|
|
||||||
|
/** 告警标题。 */
|
||||||
|
@Excel(name = "告警标题")
|
||||||
|
@ApiModelProperty("告警标题")
|
||||||
|
private String alarmTitle;
|
||||||
|
|
||||||
|
/** 告警内容详情。 */
|
||||||
|
@Excel(name = "告警内容")
|
||||||
|
@ApiModelProperty("告警内容")
|
||||||
|
private String alarmContent;
|
||||||
|
|
||||||
|
/** 告警发生位置或执行步骤。 */
|
||||||
|
@Excel(name = "告警位置")
|
||||||
|
@ApiModelProperty("告警位置/步骤")
|
||||||
|
private String alarmLocation;
|
||||||
|
|
||||||
|
/** 告警发生时间。 */
|
||||||
|
@Excel(name = "告警时间")
|
||||||
|
@ApiModelProperty("告警时间")
|
||||||
|
private Date alarmTime;
|
||||||
|
|
||||||
|
/** 处理状态:0未处理,1处理中,2已处理,3已忽略。 */
|
||||||
|
@Excel(name = "处理状态")
|
||||||
|
@ApiModelProperty("处理状态(0未处理 1处理中 2已处理 3已忽略)")
|
||||||
|
private String handleStatus;
|
||||||
|
|
||||||
|
/** 告警处理人。 */
|
||||||
|
@Excel(name = "处理人")
|
||||||
|
@ApiModelProperty("处理人")
|
||||||
|
private String handler;
|
||||||
|
|
||||||
|
/** 告警处理时间。 */
|
||||||
|
@Excel(name = "处理时间")
|
||||||
|
@ApiModelProperty("处理时间")
|
||||||
|
private Date handleTime;
|
||||||
|
|
||||||
|
/** 处理说明或备注。 */
|
||||||
|
@Excel(name = "处理说明")
|
||||||
|
@ApiModelProperty("处理说明")
|
||||||
|
private String handleRemark;
|
||||||
|
|
||||||
|
/** 告警相关图片证据。 */
|
||||||
|
@ApiModelProperty("图片证据")
|
||||||
|
private String evidenceImage;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,85 @@
|
|||||||
|
package com.cmvr.aima.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛手机管理对象 aima_phone
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("爱玛手机管理")
|
||||||
|
public class AimaPhone extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
@TableId(value = "id", type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机名称
|
||||||
|
*/
|
||||||
|
@Excel(name = "手机名称")
|
||||||
|
@ApiModelProperty("手机名称")
|
||||||
|
private String phoneName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机型号
|
||||||
|
*/
|
||||||
|
@Excel(name = "手机型号")
|
||||||
|
@ApiModelProperty("手机型号")
|
||||||
|
private String phoneModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作系统(Android/iOS)
|
||||||
|
*/
|
||||||
|
@Excel(name = "操作系统")
|
||||||
|
@ApiModelProperty("操作系统(Android/iOS)")
|
||||||
|
private String osSystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统版本
|
||||||
|
*/
|
||||||
|
@Excel(name = "系统版本")
|
||||||
|
@ApiModelProperty("系统版本")
|
||||||
|
private String osVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 规格参数
|
||||||
|
*/
|
||||||
|
@Excel(name = "规格参数")
|
||||||
|
@ApiModelProperty("规格参数")
|
||||||
|
private String specifications;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 厂商
|
||||||
|
*/
|
||||||
|
@Excel(name = "厂商")
|
||||||
|
@ApiModelProperty("厂商")
|
||||||
|
private String manufacturer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
|
@Excel(name = "状态")
|
||||||
|
@ApiModelProperty("状态(0正常 1停用)")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
package com.cmvr.aima.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务管理对象 aima_task
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("爱玛任务管理")
|
||||||
|
public class AimaTask extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
@TableId(value = "id", type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Excel(name = "任务编码")
|
||||||
|
@ApiModelProperty("任务编码")
|
||||||
|
private String taskCode;
|
||||||
|
|
||||||
|
@Excel(name = "任务名称")
|
||||||
|
@ApiModelProperty("任务名称")
|
||||||
|
private String taskName;
|
||||||
|
|
||||||
|
@Excel(name = "任务类型")
|
||||||
|
@ApiModelProperty("任务类型(1常规测试 2回归测试 3专项测试)")
|
||||||
|
private String taskType;
|
||||||
|
|
||||||
|
@ApiModelProperty("手机ID")
|
||||||
|
private String phoneId;
|
||||||
|
|
||||||
|
@ApiModelProperty("车辆ID")
|
||||||
|
private String vehicleId;
|
||||||
|
|
||||||
|
@Excel(name = "测试用例数量")
|
||||||
|
@ApiModelProperty("测试用例数量")
|
||||||
|
private Integer testCaseCount;
|
||||||
|
|
||||||
|
/** 任务配置id(关联test模块) */
|
||||||
|
@ApiModelProperty("任务配置id")
|
||||||
|
private String taskConfigId;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
package com.cmvr.aima.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务执行实例对象 aima_task_instance
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("爱玛任务执行实例")
|
||||||
|
public class AimaTaskInstance extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
@TableId(value = "id", type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Excel(name = "任务ID")
|
||||||
|
@ApiModelProperty("任务ID")
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
@Excel(name = "手机ID")
|
||||||
|
@ApiModelProperty("手机ID")
|
||||||
|
private String phoneId;
|
||||||
|
|
||||||
|
@Excel(name = "车辆ID")
|
||||||
|
@ApiModelProperty("车辆ID")
|
||||||
|
private String vehicleId;
|
||||||
|
|
||||||
|
@Excel(name = "第几次执行")
|
||||||
|
@ApiModelProperty("第几次执行")
|
||||||
|
private Integer executionNumber;
|
||||||
|
|
||||||
|
@Excel(name = "执行状态")
|
||||||
|
@ApiModelProperty("执行状态(0待执行 1执行中 2已完成 3已取消 4执行失败 5已暂停)")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/** 流程实例id(关联test模块) */
|
||||||
|
@ApiModelProperty("流程实例id")
|
||||||
|
private String taskInsId;
|
||||||
|
|
||||||
|
@Excel(name = "总用例数")
|
||||||
|
@ApiModelProperty("总用例数")
|
||||||
|
private Integer totalCases;
|
||||||
|
|
||||||
|
@Excel(name = "已完成用例数")
|
||||||
|
@ApiModelProperty("已完成用例数")
|
||||||
|
private Integer completedCases;
|
||||||
|
|
||||||
|
@Excel(name = "通过用例数")
|
||||||
|
@ApiModelProperty("通过用例数")
|
||||||
|
private Integer passedCases;
|
||||||
|
|
||||||
|
@Excel(name = "失败用例数")
|
||||||
|
@ApiModelProperty("失败用例数")
|
||||||
|
private Integer failedCases;
|
||||||
|
|
||||||
|
@Excel(name = "执行进度")
|
||||||
|
@ApiModelProperty("执行进度(百分比,保留2位小数)")
|
||||||
|
private Double progress;
|
||||||
|
|
||||||
|
@Excel(name = "开始时间")
|
||||||
|
@ApiModelProperty("开始时间")
|
||||||
|
private Date startTime;
|
||||||
|
|
||||||
|
@Excel(name = "结束时间")
|
||||||
|
@ApiModelProperty("结束时间")
|
||||||
|
private Date endTime;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package com.cmvr.aima.domain;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务与测试用例关联对象 aima_task_test_case
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class AimaTaskTestCase
|
||||||
|
{
|
||||||
|
/** 任务ID */
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
/** 测试用例ID */
|
||||||
|
private String testCaseId;
|
||||||
|
|
||||||
|
/** 排序号 */
|
||||||
|
private Integer sortOrder;
|
||||||
|
}
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
package com.cmvr.aima.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.*;
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛测试用例对象 aima_test_case
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@ApiModel("爱玛测试用例")
|
||||||
|
public class AimaTestCase extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
@TableId(value = "id", type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Excel(name = "用例编码")
|
||||||
|
@ApiModelProperty("用例编码")
|
||||||
|
private String caseCode;
|
||||||
|
|
||||||
|
@Excel(name = "用例名称")
|
||||||
|
@ApiModelProperty("用例名称")
|
||||||
|
private String caseName;
|
||||||
|
|
||||||
|
@Excel(name = "用例分类")
|
||||||
|
@ApiModelProperty("用例分类(功能测试/性能测试/安全测试等)")
|
||||||
|
private String caseCategory;
|
||||||
|
|
||||||
|
@Excel(name = "测试描述")
|
||||||
|
@ApiModelProperty("测试描述")
|
||||||
|
private String testDescription;
|
||||||
|
|
||||||
|
@Excel(name = "前置条件")
|
||||||
|
@ApiModelProperty("前置条件")
|
||||||
|
private String precondition;
|
||||||
|
|
||||||
|
@Excel(name = "测试步骤")
|
||||||
|
@ApiModelProperty("测试步骤")
|
||||||
|
private String testSteps;
|
||||||
|
|
||||||
|
@Excel(name = "预期结果")
|
||||||
|
@ApiModelProperty("预期结果")
|
||||||
|
private String expectedResult;
|
||||||
|
|
||||||
|
@Excel(name = "优先级")
|
||||||
|
@ApiModelProperty("优先级(1高 2中 3低)")
|
||||||
|
private String priority;
|
||||||
|
|
||||||
|
@Excel(name = "是否启用")
|
||||||
|
@ApiModelProperty("是否启用(0启用 1禁用)")
|
||||||
|
private String enabled;
|
||||||
|
|
||||||
|
@Excel(name = "排序号")
|
||||||
|
@ApiModelProperty("排序号")
|
||||||
|
private Integer sortOrder;
|
||||||
|
|
||||||
|
@Excel(name = "预计执行时长")
|
||||||
|
@ApiModelProperty("预计执行时长(秒)")
|
||||||
|
private Integer estimatedDuration;
|
||||||
|
|
||||||
|
/** 检测项配置id(关联test模块) */
|
||||||
|
@ApiModelProperty("检测项配置id")
|
||||||
|
private String detectItemId;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,102 @@
|
|||||||
|
package com.cmvr.aima.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.*;
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛测试日志对象 aima_test_log
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("爱玛测试日志")
|
||||||
|
@Builder
|
||||||
|
public class AimaTestLog extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
@TableId(value = "id", type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Excel(name = "任务执行实例ID")
|
||||||
|
@ApiModelProperty("任务执行实例ID")
|
||||||
|
private String taskInstanceId;
|
||||||
|
|
||||||
|
@Excel(name = "任务ID")
|
||||||
|
@ApiModelProperty("任务ID")
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
@Excel(name = "任务名称")
|
||||||
|
@ApiModelProperty("任务名称")
|
||||||
|
private String taskName;
|
||||||
|
|
||||||
|
@Excel(name = "测试用例ID")
|
||||||
|
@ApiModelProperty("测试用例ID")
|
||||||
|
private String testCaseId;
|
||||||
|
|
||||||
|
@Excel(name = "用例名称")
|
||||||
|
@ApiModelProperty("用例名称")
|
||||||
|
private String caseName;
|
||||||
|
|
||||||
|
@Excel(name = "日志级别")
|
||||||
|
@ApiModelProperty("日志级别(DEBUG/INFO/WARN/ERROR)")
|
||||||
|
private String logLevel;
|
||||||
|
|
||||||
|
@Excel(name = "日志类型")
|
||||||
|
@ApiModelProperty("日志类型(执行日志/系统日志/异常日志)")
|
||||||
|
private String logType;
|
||||||
|
|
||||||
|
@Excel(name = "日志内容")
|
||||||
|
@ApiModelProperty("日志内容")
|
||||||
|
private String logContent;
|
||||||
|
|
||||||
|
@Excel(name = "日志时间")
|
||||||
|
@ApiModelProperty("日志时间")
|
||||||
|
private Date logTime;
|
||||||
|
|
||||||
|
@Excel(name = "执行步骤")
|
||||||
|
@ApiModelProperty("执行步骤")
|
||||||
|
private String executionStep;
|
||||||
|
|
||||||
|
@Excel(name = "实际结果")
|
||||||
|
@ApiModelProperty("实际结果")
|
||||||
|
private String actualResult;
|
||||||
|
|
||||||
|
@Excel(name = "测试结果")
|
||||||
|
@ApiModelProperty("测试结果(0未执行 1通过 2失败 3跳过)")
|
||||||
|
private String testStatus;
|
||||||
|
|
||||||
|
@ApiModelProperty("截图URL")
|
||||||
|
private String screenshotUrl;
|
||||||
|
|
||||||
|
@ApiModelProperty("视频URL")
|
||||||
|
private String videoUrl;
|
||||||
|
|
||||||
|
@ApiModelProperty("错误堆栈")
|
||||||
|
private String errorStack;
|
||||||
|
|
||||||
|
@Excel(name = "执行耗时")
|
||||||
|
@ApiModelProperty("执行耗时(毫秒)")
|
||||||
|
private Long durationMs;
|
||||||
|
|
||||||
|
@Excel(name = "进度")
|
||||||
|
@ApiModelProperty("执行进度(百分比)")
|
||||||
|
private Double progress;
|
||||||
|
|
||||||
|
@Excel(name = "状态")
|
||||||
|
@ApiModelProperty("执行状态(0待执行 1执行中 2已完成 3已取消 4执行失败 5已暂停)")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
package com.cmvr.aima.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛车辆管理对象 aima_vehicle
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("爱玛车辆管理")
|
||||||
|
public class AimaVehicle extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
@TableId(value = "id", type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Excel(name = "车架号")
|
||||||
|
@ApiModelProperty("车架号(VIN)")
|
||||||
|
private String vin;
|
||||||
|
|
||||||
|
@Excel(name = "车型")
|
||||||
|
@ApiModelProperty("车型")
|
||||||
|
private String vehicleModel;
|
||||||
|
|
||||||
|
@Excel(name = "车辆名称")
|
||||||
|
@ApiModelProperty("车辆名称")
|
||||||
|
private String vehicleName;
|
||||||
|
|
||||||
|
@Excel(name = "颜色")
|
||||||
|
@ApiModelProperty("颜色")
|
||||||
|
private String color;
|
||||||
|
|
||||||
|
@Excel(name = "生产日期")
|
||||||
|
@ApiModelProperty("生产日期")
|
||||||
|
private Date productionDate;
|
||||||
|
|
||||||
|
@Excel(name = "状态")
|
||||||
|
@ApiModelProperty("状态(0正常 1停用)")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.cmvr.aima.domain.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务实例查询入参DTO
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel("爱玛任务实例查询条件")
|
||||||
|
public class AimaTaskInstanceQuery {
|
||||||
|
|
||||||
|
@ApiModelProperty("任务ID")
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
@ApiModelProperty("手机ID")
|
||||||
|
private String phoneId;
|
||||||
|
|
||||||
|
@ApiModelProperty("车辆ID")
|
||||||
|
private String vehicleId;
|
||||||
|
|
||||||
|
@ApiModelProperty("单个状态(兼容原有精确查询)")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ApiModelProperty("多状态集合,in查询用:0待执行 1执行中 2已完成 3已取消 4执行失败 5已暂停")
|
||||||
|
private List<Integer> statusList;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
package com.cmvr.aima.domain.vo;
|
||||||
|
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务执行实例视图对象(包含关联信息)
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("爱玛任务执行实例视图对象")
|
||||||
|
public class
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AimaTaskInstanceVo extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** id */
|
||||||
|
@ApiModelProperty("id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/** 任务ID */
|
||||||
|
@Excel(name = "任务ID")
|
||||||
|
@ApiModelProperty("任务ID")
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
/** 任务名称 */
|
||||||
|
@Excel(name = "任务名称")
|
||||||
|
@ApiModelProperty("任务名称")
|
||||||
|
private String taskName;
|
||||||
|
|
||||||
|
/** 任务编码 */
|
||||||
|
@Excel(name = "任务编码")
|
||||||
|
@ApiModelProperty("任务编码")
|
||||||
|
private String taskCode;
|
||||||
|
|
||||||
|
/** 手机ID */
|
||||||
|
@ApiModelProperty("手机ID")
|
||||||
|
private String phoneId;
|
||||||
|
|
||||||
|
/** 手机名称 */
|
||||||
|
@Excel(name = "手机名称")
|
||||||
|
@ApiModelProperty("手机名称")
|
||||||
|
private String phoneName;
|
||||||
|
|
||||||
|
/** 车辆ID */
|
||||||
|
@ApiModelProperty("车辆ID")
|
||||||
|
private String vehicleId;
|
||||||
|
|
||||||
|
/** 车辆名称 */
|
||||||
|
@Excel(name = "车辆名称")
|
||||||
|
@ApiModelProperty("车辆名称")
|
||||||
|
private String vehicleName;
|
||||||
|
|
||||||
|
/** 车架号 */
|
||||||
|
@Excel(name = "车架号")
|
||||||
|
@ApiModelProperty("车架号")
|
||||||
|
private String vin;
|
||||||
|
|
||||||
|
/** 第几次执行 */
|
||||||
|
@Excel(name = "执行次数")
|
||||||
|
@ApiModelProperty("第几次执行")
|
||||||
|
private Integer executionNumber;
|
||||||
|
|
||||||
|
/** 执行状态 */
|
||||||
|
@Excel(name = "执行状态")
|
||||||
|
@ApiModelProperty("执行状态(0待执行 1执行中 2已完成 3已取消 4执行失败 5已暂停)")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/** 流程实例id */
|
||||||
|
@ApiModelProperty("流程实例id")
|
||||||
|
private String taskInsId;
|
||||||
|
|
||||||
|
/** 总用例数 */
|
||||||
|
@Excel(name = "总用例数")
|
||||||
|
@ApiModelProperty("总用例数")
|
||||||
|
private Integer totalCases;
|
||||||
|
|
||||||
|
/** 已完成用例数 */
|
||||||
|
@Excel(name = "已完成")
|
||||||
|
@ApiModelProperty("已完成用例数")
|
||||||
|
private Integer completedCases;
|
||||||
|
|
||||||
|
/** 通过用例数 */
|
||||||
|
@Excel(name = "通过数")
|
||||||
|
@ApiModelProperty("通过用例数")
|
||||||
|
private Integer passedCases;
|
||||||
|
|
||||||
|
/** 失败用例数 */
|
||||||
|
@Excel(name = "失败数")
|
||||||
|
@ApiModelProperty("失败用例数")
|
||||||
|
private Integer failedCases;
|
||||||
|
|
||||||
|
/** 执行进度 */
|
||||||
|
@Excel(name = "执行进度")
|
||||||
|
@ApiModelProperty("执行进度(百分比,保留2位小数)")
|
||||||
|
private Double progress;
|
||||||
|
|
||||||
|
/** 开始时间 */
|
||||||
|
@Excel(name = "开始时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@ApiModelProperty("开始时间")
|
||||||
|
private Date startTime;
|
||||||
|
|
||||||
|
/** 结束时间 */
|
||||||
|
@Excel(name = "结束时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@ApiModelProperty("结束时间")
|
||||||
|
private Date endTime;
|
||||||
|
|
||||||
|
/** 创建人昵称 */
|
||||||
|
@Excel(name = "创建人昵称")
|
||||||
|
@ApiModelProperty("创建人昵称")
|
||||||
|
private String createByName;
|
||||||
|
|
||||||
|
/** 修改人昵称 */
|
||||||
|
@Excel(name = "修改人昵称")
|
||||||
|
@ApiModelProperty("修改人昵称")
|
||||||
|
private String updateByName;
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
package com.cmvr.aima.domain.vo;
|
||||||
|
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务视图对象(包含关联信息)
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("爱玛任务视图对象")
|
||||||
|
public class AimaTaskVo extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** id */
|
||||||
|
@ApiModelProperty("id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/** 任务编码 */
|
||||||
|
@Excel(name = "任务编码")
|
||||||
|
@ApiModelProperty("任务编码")
|
||||||
|
private String taskCode;
|
||||||
|
|
||||||
|
/** 任务名称 */
|
||||||
|
@Excel(name = "任务名称")
|
||||||
|
@ApiModelProperty("任务名称")
|
||||||
|
private String taskName;
|
||||||
|
|
||||||
|
/** 任务类型 */
|
||||||
|
@Excel(name = "任务类型")
|
||||||
|
@ApiModelProperty("任务类型(1常规测试 2回归测试 3专项测试)")
|
||||||
|
private String taskType;
|
||||||
|
|
||||||
|
/** 手机ID */
|
||||||
|
@ApiModelProperty("手机ID")
|
||||||
|
private String phoneId;
|
||||||
|
|
||||||
|
/** 手机名称 */
|
||||||
|
@Excel(name = "手机名称")
|
||||||
|
@ApiModelProperty("手机名称")
|
||||||
|
private String phoneName;
|
||||||
|
|
||||||
|
/** 车辆ID */
|
||||||
|
@ApiModelProperty("车辆ID")
|
||||||
|
private String vehicleId;
|
||||||
|
|
||||||
|
/** 测试用例数量 */
|
||||||
|
@Excel(name = "测试用例数量")
|
||||||
|
@ApiModelProperty("测试用例数量")
|
||||||
|
private Integer testCaseCount;
|
||||||
|
|
||||||
|
/** 任务配置id */
|
||||||
|
@ApiModelProperty("任务配置id")
|
||||||
|
private String taskConfigId;
|
||||||
|
|
||||||
|
/** 创建人昵称 */
|
||||||
|
@Excel(name = "创建人昵称")
|
||||||
|
@ApiModelProperty("创建人昵称")
|
||||||
|
private String createByName;
|
||||||
|
|
||||||
|
/** 修改人昵称 */
|
||||||
|
@Excel(name = "修改人昵称")
|
||||||
|
@ApiModelProperty("修改人昵称")
|
||||||
|
private String updateByName;
|
||||||
|
}
|
||||||
@ -0,0 +1,100 @@
|
|||||||
|
package com.cmvr.aima.domain.vo;
|
||||||
|
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛测试用例视图对象(包含关联信息)
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("爱玛测试用例视图对象")
|
||||||
|
public class AimaTestCaseVo extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** id */
|
||||||
|
@ApiModelProperty("id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/** 用例编码 */
|
||||||
|
@Excel(name = "用例编码")
|
||||||
|
@ApiModelProperty("用例编码")
|
||||||
|
private String caseCode;
|
||||||
|
|
||||||
|
/** 用例名称 */
|
||||||
|
@Excel(name = "用例名称")
|
||||||
|
@ApiModelProperty("用例名称")
|
||||||
|
private String caseName;
|
||||||
|
|
||||||
|
/** 用例分类 */
|
||||||
|
@Excel(name = "用例分类")
|
||||||
|
@ApiModelProperty("用例分类(功能测试/性能测试/安全测试等)")
|
||||||
|
private String caseCategory;
|
||||||
|
|
||||||
|
/** 测试描述 */
|
||||||
|
@ApiModelProperty("测试描述")
|
||||||
|
private String testDescription;
|
||||||
|
|
||||||
|
/** 前置条件 */
|
||||||
|
@ApiModelProperty("前置条件")
|
||||||
|
private String precondition;
|
||||||
|
|
||||||
|
/** 测试步骤 */
|
||||||
|
@ApiModelProperty("测试步骤")
|
||||||
|
private String testSteps;
|
||||||
|
|
||||||
|
/** 预期结果 */
|
||||||
|
@ApiModelProperty("预期结果")
|
||||||
|
private String expectedResult;
|
||||||
|
|
||||||
|
/** 优先级 */
|
||||||
|
@Excel(name = "优先级")
|
||||||
|
@ApiModelProperty("优先级(1高 2中 3低)")
|
||||||
|
private String priority;
|
||||||
|
|
||||||
|
/** 是否启用 */
|
||||||
|
@Excel(name = "是否启用")
|
||||||
|
@ApiModelProperty("是否启用(0启用 1禁用)")
|
||||||
|
private String enabled;
|
||||||
|
|
||||||
|
/** 排序号 */
|
||||||
|
@Excel(name = "排序号")
|
||||||
|
@ApiModelProperty("排序号")
|
||||||
|
private Integer sortOrder;
|
||||||
|
|
||||||
|
/** 预计执行时长 */
|
||||||
|
@Excel(name = "预计执行时长")
|
||||||
|
@ApiModelProperty("预计执行时长(秒)")
|
||||||
|
private Integer estimatedDuration;
|
||||||
|
|
||||||
|
/** 检测项配置id */
|
||||||
|
@ApiModelProperty("检测项配置id")
|
||||||
|
private String detectItemId;
|
||||||
|
|
||||||
|
/** 配置状态 */
|
||||||
|
@Excel(name = "配置状态")
|
||||||
|
@ApiModelProperty("配置状态(0未部署 1已部署)")
|
||||||
|
private String configStatus;
|
||||||
|
|
||||||
|
/** 创建人昵称 */
|
||||||
|
@Excel(name = "创建人昵称")
|
||||||
|
@ApiModelProperty("创建人昵称")
|
||||||
|
private String createByName;
|
||||||
|
|
||||||
|
/** 修改人昵称 */
|
||||||
|
@Excel(name = "修改人昵称")
|
||||||
|
@ApiModelProperty("修改人昵称")
|
||||||
|
private String updateByName;
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.cmvr.aima.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛测试日志类型枚举
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum AimaLogTypeEnum {
|
||||||
|
TEXT(1, "文字"),
|
||||||
|
IMAGE(2, "图片"),
|
||||||
|
VIDEO(3, "视频"),
|
||||||
|
AUDIO(4, "音频");
|
||||||
|
|
||||||
|
private final int code;
|
||||||
|
private final String desc;
|
||||||
|
|
||||||
|
public static AimaLogTypeEnum fromCode(int code) {
|
||||||
|
for (AimaLogTypeEnum type : values()) {
|
||||||
|
if (type.code == code) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.cmvr.aima.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务状态枚举
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum AimaTaskStatusEnum {
|
||||||
|
// 未执行
|
||||||
|
NOT_STARTED(5, "未执行"),
|
||||||
|
SUCCESS(0, "已完成"),
|
||||||
|
RUNNING(1, "执行中"),
|
||||||
|
FAILED(2, "失败"),
|
||||||
|
PAUSED(3, "已暂停"),
|
||||||
|
STOPPED(4, "已终止");
|
||||||
|
|
||||||
|
private final int code;
|
||||||
|
private final String desc;
|
||||||
|
|
||||||
|
public static AimaTaskStatusEnum fromCode(int code) {
|
||||||
|
for (AimaTaskStatusEnum status : values()) {
|
||||||
|
if (status.code == code) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,206 @@
|
|||||||
|
package com.cmvr.aima.listener;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.cmvr.common.utils.DateUtils;
|
||||||
|
import com.cmvr.framework.websocket.service.MessagePushService;
|
||||||
|
import com.cmvr.aima.domain.AimaTaskInstance;
|
||||||
|
import com.cmvr.aima.domain.AimaTestLog;
|
||||||
|
import com.cmvr.aima.enums.AimaTaskStatusEnum;
|
||||||
|
import com.cmvr.aima.service.IAimaTaskInstanceService;
|
||||||
|
import com.cmvr.aima.service.IAimaTestLogService;
|
||||||
|
import com.cmvr.test.flow.runtime.event.FlowExecutionEvent;
|
||||||
|
import com.cmvr.test.flow.runtime.event.FlowExecutionListener;
|
||||||
|
import com.cmvr.test.flow.runtime.event.FlowExecutionModuleCodes;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛测试工作流执行监听器
|
||||||
|
* 监听流程引擎事件,自动记录测试日志和更新任务状态
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class AimaFlowExecutionListener implements FlowExecutionListener {
|
||||||
|
private final IAimaTaskInstanceService aimaTaskInstanceService;
|
||||||
|
private final IAimaTestLogService aimaTestLogService;
|
||||||
|
private final MessagePushService messagePushService;
|
||||||
|
|
||||||
|
/** key:itemId, value:已完成节点集合 */
|
||||||
|
private final Map<String, Set<String>> itemNodeExecutMap = new HashMap<>();
|
||||||
|
/** key:taskInsId(流程实例id), value:已执行item集合 */
|
||||||
|
private final Map<String, Set<String>> taskItemExecutMap = new HashMap<>();
|
||||||
|
|
||||||
|
public AimaFlowExecutionListener(IAimaTaskInstanceService aimaTaskInstanceService,
|
||||||
|
IAimaTestLogService aimaTestLogService,
|
||||||
|
MessagePushService messagePushService) {
|
||||||
|
this.aimaTaskInstanceService = aimaTaskInstanceService;
|
||||||
|
this.aimaTestLogService = aimaTestLogService;
|
||||||
|
this.messagePushService = messagePushService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModuleCode() {
|
||||||
|
return FlowExecutionModuleCodes.AIMA;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(FlowExecutionEvent event) {
|
||||||
|
String instId = event.getInstId();
|
||||||
|
String itemId = event.getItemId();
|
||||||
|
String nodeId = event.getNodeId();
|
||||||
|
if (StrUtil.isBlank(instId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.节点完成才记录当前item下node
|
||||||
|
if (StrUtil.isNotBlank(itemId) && StrUtil.isNotBlank(nodeId)
|
||||||
|
&& FlowExecutionEvent.EventType.NODE_COMPLETED == event.getEventType()) {
|
||||||
|
itemNodeExecutMap.computeIfAbsent(itemId, k -> new HashSet<>()).add(nodeId);
|
||||||
|
}
|
||||||
|
// 任意事件:当前任务绑定item(item一启动就入Map)
|
||||||
|
if (StrUtil.isNotBlank(instId) && StrUtil.isNotBlank(itemId)) {
|
||||||
|
taskItemExecutMap.computeIfAbsent(instId, k -> new HashSet<>()).add(itemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询任务实例
|
||||||
|
AimaTaskInstance taskInstance = aimaTaskInstanceService.lambdaQuery()
|
||||||
|
.eq(AimaTaskInstance::getTaskInsId, instId)
|
||||||
|
.one();
|
||||||
|
if (taskInstance == null) {
|
||||||
|
log.warn("未查询到爱玛测试实例,taskInsId:{}", instId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int targetStatus = AimaTaskStatusEnum.RUNNING.getCode();
|
||||||
|
boolean needUpdateDb = false;
|
||||||
|
Date now = DateUtils.getNowDate();
|
||||||
|
|
||||||
|
switch (event.getEventType()) {
|
||||||
|
case TASK_COMPLETED:
|
||||||
|
targetStatus = AimaTaskStatusEnum.SUCCESS.getCode();
|
||||||
|
needUpdateDb = true;
|
||||||
|
clearCache(instId);
|
||||||
|
pushCompleteMsg(taskInstance.getId(), now, targetStatus);
|
||||||
|
break;
|
||||||
|
case TASK_FAILED:
|
||||||
|
targetStatus = AimaTaskStatusEnum.FAILED.getCode();
|
||||||
|
needUpdateDb = true;
|
||||||
|
clearCache(instId);
|
||||||
|
break;
|
||||||
|
case NODE_COMPLETED:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needUpdateDb) {
|
||||||
|
taskInstance.setStatus(targetStatus);
|
||||||
|
taskInstance.setEndTime(now);
|
||||||
|
aimaTaskInstanceService.updateById(taskInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节点推送 - 记录日志
|
||||||
|
if (StrUtil.isNotBlank(nodeId)) {
|
||||||
|
int totalCases = taskInstance.getTotalCases() == null ? 0 : taskInstance.getTotalCases();
|
||||||
|
double progress = 0D;
|
||||||
|
if (totalCases > 0) {
|
||||||
|
// 当前任务已执行item数量
|
||||||
|
Set<String> itemSet = taskItemExecutMap.getOrDefault(instId, new HashSet<>());
|
||||||
|
int itemTotal = itemSet.size();
|
||||||
|
int finishedItemNum = itemTotal - 1;
|
||||||
|
|
||||||
|
// 当前item已完成节点数
|
||||||
|
Set<String> finishedNodeSet = itemNodeExecutMap.getOrDefault(itemId, new HashSet<>());
|
||||||
|
int finishedNode = finishedNodeSet.size();
|
||||||
|
int totalNode = event.getNodeCount() == 0 ? 1 : event.getNodeCount();
|
||||||
|
|
||||||
|
// 已完整跑完用例占比
|
||||||
|
double itemTotalRatio = finishedItemNum / (double) totalCases;
|
||||||
|
// 当前运行item内部节点占比
|
||||||
|
double innerRatio = finishedNode / (double) totalNode / totalCases;
|
||||||
|
|
||||||
|
// 防止循环节点进度超限
|
||||||
|
double singleItemBase = 1d / totalCases;
|
||||||
|
innerRatio = Math.max(singleItemBase - 0.01, innerRatio);
|
||||||
|
|
||||||
|
progress = (itemTotalRatio + innerRatio) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
String info = event.getEventType() == FlowExecutionEvent.EventType.NODE_STARTED ? "开始执行" : "执行完成";
|
||||||
|
String logId = UUID.randomUUID().toString().replace("-", "");
|
||||||
|
// 四舍五入保留2位小数
|
||||||
|
progress = Math.round(progress * 100) / 100.0;
|
||||||
|
|
||||||
|
// 保存日志到数据库
|
||||||
|
AimaTestLog testLog = AimaTestLog.builder()
|
||||||
|
.id(logId)
|
||||||
|
.taskInstanceId(taskInstance.getId())
|
||||||
|
.taskId(taskInstance.getTaskId())
|
||||||
|
.testCaseId(itemId)
|
||||||
|
.logLevel("INFO")
|
||||||
|
.logType("执行日志")
|
||||||
|
.logContent("节点【" + event.getNodeName() + "】" + info)
|
||||||
|
.logTime(now)
|
||||||
|
.status(targetStatus)
|
||||||
|
.executionStep(event.getNodeName())
|
||||||
|
.testStatus("0") // 0未执行
|
||||||
|
.durationMs(0L)
|
||||||
|
.progress( progress)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
aimaTestLogService.insertAimaTestLog(testLog);
|
||||||
|
log.info("爱玛测试日志保存成功,logId:{},taskInstanceId:{},nodeId:{}", logId, taskInstance.getId(), nodeId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("爱玛测试日志保存失败,taskInstanceId:{},nodeId:{}", taskInstance.getId(), nodeId, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
messagePushService.pushToChannel("AimaTaskInstance", testLog);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("消息推送异常,无订阅忽略,itemId:{}", itemId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 任务结束统一清理缓存 */
|
||||||
|
private void clearCache(String taskInsId) {
|
||||||
|
Set<String> itemList = taskItemExecutMap.getOrDefault(taskInsId, new HashSet<>());
|
||||||
|
itemList.forEach(itemNodeExecutMap::remove);
|
||||||
|
taskItemExecutMap.remove(taskInsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推送完成任务信息
|
||||||
|
*/
|
||||||
|
public void pushCompleteMsg(String dbInsId, Date now, int targetStatus) {
|
||||||
|
String logId = UUID.randomUUID().toString().replace("-", "");
|
||||||
|
|
||||||
|
// 保存完成日志
|
||||||
|
AimaTestLog testLog = AimaTestLog.builder()
|
||||||
|
.id(logId)
|
||||||
|
.taskInstanceId(dbInsId)
|
||||||
|
.logLevel("INFO")
|
||||||
|
.logType("系统日志")
|
||||||
|
.logContent("任务执行完成")
|
||||||
|
.logTime(now)
|
||||||
|
.status(targetStatus)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
aimaTestLogService.insertAimaTestLog(testLog);
|
||||||
|
log.info("任务完成日志保存成功,logId:{},taskInstanceId:{}", logId, dbInsId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("任务完成日志保存失败,taskInstanceId:{}", dbInsId, e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
messagePushService.pushToChannel("AimaTaskInstance", testLog);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("消息推送异常,无订阅忽略,insId:{}", dbInsId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package com.cmvr.aima.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaAlarm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛告警管理Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface AimaAlarmMapper extends BaseMapper<AimaAlarm> {
|
||||||
|
/**
|
||||||
|
* 查询爱玛告警管理
|
||||||
|
*
|
||||||
|
* @param id 爱玛告警管理主键
|
||||||
|
* @return 爱玛告警管理
|
||||||
|
*/
|
||||||
|
AimaAlarm selectAimaAlarmById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛告警管理列表
|
||||||
|
*
|
||||||
|
* @param aimaAlarm 爱玛告警管理
|
||||||
|
* @return 爱玛告警管理集合
|
||||||
|
*/
|
||||||
|
List<AimaAlarm> selectAimaAlarmList(AimaAlarm aimaAlarm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛告警管理
|
||||||
|
*
|
||||||
|
* @param aimaAlarm 爱玛告警管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertAimaAlarm(AimaAlarm aimaAlarm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛告警管理
|
||||||
|
*
|
||||||
|
* @param aimaAlarm 爱玛告警管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateAimaAlarm(AimaAlarm aimaAlarm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛告警管理
|
||||||
|
*
|
||||||
|
* @param id 爱玛告警管理主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaAlarmById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛告警管理
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaAlarmByIds(String[] ids);
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package com.cmvr.aima.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaPhone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛手机管理Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface AimaPhoneMapper extends BaseMapper<AimaPhone> {
|
||||||
|
/**
|
||||||
|
* 查询爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param id 爱玛手机管理主键
|
||||||
|
* @return 爱玛手机管理
|
||||||
|
*/
|
||||||
|
AimaPhone selectAimaPhoneById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛手机管理列表
|
||||||
|
*
|
||||||
|
* @param aimaPhone 爱玛手机管理
|
||||||
|
* @return 爱玛手机管理集合
|
||||||
|
*/
|
||||||
|
List<AimaPhone> selectAimaPhoneList(AimaPhone aimaPhone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param aimaPhone 爱玛手机管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertAimaPhone(AimaPhone aimaPhone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param aimaPhone 爱玛手机管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateAimaPhone(AimaPhone aimaPhone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param id 爱玛手机管理主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaPhoneById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaPhoneByIds(String[] ids);
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
package com.cmvr.aima.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaTaskInstance;
|
||||||
|
import com.cmvr.aima.domain.dto.AimaTaskInstanceQuery;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTaskInstanceVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务执行实例Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface AimaTaskInstanceMapper extends BaseMapper<AimaTaskInstance> {
|
||||||
|
/**
|
||||||
|
* 查询爱玛任务执行实例
|
||||||
|
*
|
||||||
|
* @param id 爱玛任务执行实例主键
|
||||||
|
* @return 爱玛任务执行实例
|
||||||
|
*/
|
||||||
|
AimaTaskInstance selectAimaTaskInstanceById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛任务执行实例列表
|
||||||
|
*
|
||||||
|
* @param aimaTaskInstance 爱玛任务执行实例
|
||||||
|
* @return 爱玛任务执行实例集合
|
||||||
|
*/
|
||||||
|
List<AimaTaskInstance> selectAimaTaskInstanceList(AimaTaskInstance aimaTaskInstance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛任务执行实例视图列表(包含关联信息)
|
||||||
|
*
|
||||||
|
* @param query 查询条件
|
||||||
|
* @return 爱玛任务执行实例视图集合
|
||||||
|
*/
|
||||||
|
List<AimaTaskInstanceVo> selectAimaTaskInstanceVoList(AimaTaskInstanceQuery query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛任务执行实例
|
||||||
|
*
|
||||||
|
* @param aimaTaskInstance 爱玛任务执行实例
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertAimaTaskInstance(AimaTaskInstance aimaTaskInstance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛任务执行实例
|
||||||
|
*
|
||||||
|
* @param aimaTaskInstance 爱玛任务执行实例
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateAimaTaskInstance(AimaTaskInstance aimaTaskInstance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛任务执行实例
|
||||||
|
*
|
||||||
|
* @param id 爱玛任务执行实例主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaTaskInstanceById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛任务执行实例
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaTaskInstanceByIds(String[] ids);
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
package com.cmvr.aima.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaTask;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTaskVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务管理Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface AimaTaskMapper extends BaseMapper<AimaTask> {
|
||||||
|
/**
|
||||||
|
* 查询爱玛任务管理
|
||||||
|
*
|
||||||
|
* @param id 爱玛任务管理主键
|
||||||
|
* @return 爱玛任务管理
|
||||||
|
*/
|
||||||
|
AimaTask selectAimaTaskById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛任务管理列表
|
||||||
|
*
|
||||||
|
* @param aimaTask 爱玛任务管理
|
||||||
|
* @return 爱玛任务管理集合
|
||||||
|
*/
|
||||||
|
List<AimaTask> selectAimaTaskList(AimaTask aimaTask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛任务视图列表(包含关联信息)
|
||||||
|
*
|
||||||
|
* @param aimaTask 爱玛任务管理
|
||||||
|
* @return 爱玛任务视图集合
|
||||||
|
*/
|
||||||
|
List<AimaTaskVo> selectAimaTaskVoList(AimaTask aimaTask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛任务管理
|
||||||
|
*
|
||||||
|
* @param aimaTask 爱玛任务管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertAimaTask(AimaTask aimaTask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛任务管理
|
||||||
|
*
|
||||||
|
* @param aimaTask 爱玛任务管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateAimaTask(AimaTask aimaTask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛任务管理
|
||||||
|
*
|
||||||
|
* @param id 爱玛任务管理主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaTaskById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛任务管理
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaTaskByIds(String[] ids);
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package com.cmvr.aima.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.github.yulichang.base.MPJBaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import com.cmvr.aima.domain.AimaTaskTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务与测试用例关联Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface AimaTaskTestCaseMapper extends MPJBaseMapper<AimaTaskTestCase>
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 批量插入任务-测试用例关联
|
||||||
|
*
|
||||||
|
* @param list 任务-测试用例关联列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
void batchInsertTaskTestCase(@Param("list") List<AimaTaskTestCase> list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据任务ID删除关联
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
void deleteTaskTestCaseByTaskId(String taskId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据任务ID查询测试用例ID列表
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 测试用例ID列表
|
||||||
|
*/
|
||||||
|
List<String> selectTestCaseIdsByTaskId(String taskId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除任务-测试用例关联
|
||||||
|
*
|
||||||
|
* @param taskIds 需要删除的任务ID数组
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
void deleteTaskTestCaseByTaskIds(String[] taskIds);
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
package com.cmvr.aima.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaTestCase;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTestCaseVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛测试用例Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface AimaTestCaseMapper extends BaseMapper<AimaTestCase> {
|
||||||
|
/**
|
||||||
|
* 查询爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param id 爱玛测试用例主键
|
||||||
|
* @return 爱玛测试用例
|
||||||
|
*/
|
||||||
|
AimaTestCase selectAimaTestCaseById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛测试用例列表
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 爱玛测试用例集合
|
||||||
|
*/
|
||||||
|
List<AimaTestCase> selectAimaTestCaseList(AimaTestCase aimaTestCase);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛测试用例视图列表(包含关联信息)
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 爱玛测试用例视图集合
|
||||||
|
*/
|
||||||
|
List<AimaTestCaseVo> selectAimaTestCaseVoList(AimaTestCase aimaTestCase);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertAimaTestCase(AimaTestCase aimaTestCase);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateAimaTestCase(AimaTestCase aimaTestCase);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param id 爱玛测试用例主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaTestCaseById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaTestCaseByIds(String[] ids);
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package com.cmvr.aima.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaTestLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛测试日志Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface AimaTestLogMapper extends BaseMapper<AimaTestLog> {
|
||||||
|
/**
|
||||||
|
* 查询爱玛测试日志
|
||||||
|
*
|
||||||
|
* @param id 爱玛测试日志主键
|
||||||
|
* @return 爱玛测试日志
|
||||||
|
*/
|
||||||
|
AimaTestLog selectAimaTestLogById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛测试日志列表
|
||||||
|
*
|
||||||
|
* @param aimaTestLog 爱玛测试日志
|
||||||
|
* @return 爱玛测试日志集合
|
||||||
|
*/
|
||||||
|
List<AimaTestLog> selectAimaTestLogList(AimaTestLog aimaTestLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛测试日志
|
||||||
|
*
|
||||||
|
* @param aimaTestLog 爱玛测试日志
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertAimaTestLog(AimaTestLog aimaTestLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛测试日志
|
||||||
|
*
|
||||||
|
* @param aimaTestLog 爱玛测试日志
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateAimaTestLog(AimaTestLog aimaTestLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛测试日志
|
||||||
|
*
|
||||||
|
* @param id 爱玛测试日志主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaTestLogById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛测试日志
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaTestLogByIds(String[] ids);
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package com.cmvr.aima.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaVehicle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛车辆管理Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface AimaVehicleMapper extends BaseMapper<AimaVehicle> {
|
||||||
|
/**
|
||||||
|
* 查询爱玛车辆管理
|
||||||
|
*
|
||||||
|
* @param id 爱玛车辆管理主键
|
||||||
|
* @return 爱玛车辆管理
|
||||||
|
*/
|
||||||
|
AimaVehicle selectAimaVehicleById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛车辆管理列表
|
||||||
|
*
|
||||||
|
* @param aimaVehicle 爱玛车辆管理
|
||||||
|
* @return 爱玛车辆管理集合
|
||||||
|
*/
|
||||||
|
List<AimaVehicle> selectAimaVehicleList(AimaVehicle aimaVehicle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛车辆管理
|
||||||
|
*
|
||||||
|
* @param aimaVehicle 爱玛车辆管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertAimaVehicle(AimaVehicle aimaVehicle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛车辆管理
|
||||||
|
*
|
||||||
|
* @param aimaVehicle 爱玛车辆管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateAimaVehicle(AimaVehicle aimaVehicle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛车辆管理
|
||||||
|
*
|
||||||
|
* @param id 爱玛车辆管理主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaVehicleById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛车辆管理
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaVehicleByIds(String[] ids);
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.cmvr.aima.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.cmvr.aima.domain.AimaAlarm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛告警管理Service接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface IAimaAlarmService {
|
||||||
|
AimaAlarm selectAimaAlarmById(String id);
|
||||||
|
List<AimaAlarm> selectAimaAlarmList(AimaAlarm aimaAlarm);
|
||||||
|
int insertAimaAlarm(AimaAlarm aimaAlarm);
|
||||||
|
int updateAimaAlarm(AimaAlarm aimaAlarm);
|
||||||
|
int deleteAimaAlarmByIds(String[] ids);
|
||||||
|
int deleteAimaAlarmById(String id);
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package com.cmvr.aima.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.cmvr.aima.domain.AimaPhone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛手机管理Service接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface IAimaPhoneService {
|
||||||
|
/**
|
||||||
|
* 查询爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param id 爱玛手机管理主键
|
||||||
|
* @return 爱玛手机管理
|
||||||
|
*/
|
||||||
|
AimaPhone selectAimaPhoneById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛手机管理列表
|
||||||
|
*
|
||||||
|
* @param aimaPhone 爱玛手机管理
|
||||||
|
* @return 爱玛手机管理集合
|
||||||
|
*/
|
||||||
|
List<AimaPhone> selectAimaPhoneList(AimaPhone aimaPhone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param aimaPhone 爱玛手机管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertAimaPhone(AimaPhone aimaPhone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param aimaPhone 爱玛手机管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateAimaPhone(AimaPhone aimaPhone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的爱玛手机管理主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaPhoneByIds(String[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛手机管理信息
|
||||||
|
*
|
||||||
|
* @param id 爱玛手机管理主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaPhoneById(String id);
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
package com.cmvr.aima.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.cmvr.aima.domain.AimaTaskInstance;
|
||||||
|
import com.cmvr.aima.domain.dto.AimaTaskInstanceQuery;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTaskInstanceVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务执行实例Service接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface IAimaTaskInstanceService extends IService<AimaTaskInstance> {
|
||||||
|
AimaTaskInstance selectAimaTaskInstanceById(String id);
|
||||||
|
List<AimaTaskInstance> selectAimaTaskInstanceList(AimaTaskInstance aimaTaskInstance);
|
||||||
|
List<AimaTaskInstanceVo> selectAimaTaskInstanceVoList(AimaTaskInstanceQuery query);
|
||||||
|
int insertAimaTaskInstance(AimaTaskInstance aimaTaskInstance);
|
||||||
|
int updateAimaTaskInstance(AimaTaskInstance aimaTaskInstance);
|
||||||
|
int deleteAimaTaskInstanceByIds(String[] ids);
|
||||||
|
int deleteAimaTaskInstanceById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始执行任务实例
|
||||||
|
*
|
||||||
|
* @param id 任务实例ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int startInstance(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停任务实例
|
||||||
|
*
|
||||||
|
* @param id 任务实例ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int pauseInstance(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终止任务实例
|
||||||
|
*
|
||||||
|
* @param id 任务实例ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int stopInstance(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复任务实例(从暂停恢复为执行中)
|
||||||
|
*
|
||||||
|
* @param id 任务实例ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int resumeInstance(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新任务实例进度
|
||||||
|
*
|
||||||
|
* @param instanceId 任务实例ID
|
||||||
|
* @param progress 执行进度(百分比,保留2位小数)
|
||||||
|
*/
|
||||||
|
void updateProgress(String instanceId, Double progress);
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
package com.cmvr.aima.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.cmvr.aima.domain.AimaTask;
|
||||||
|
import com.cmvr.aima.domain.AimaTestCase;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTaskVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务管理Service接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface IAimaTaskService {
|
||||||
|
AimaTask selectAimaTaskById(String id);
|
||||||
|
List<AimaTask> selectAimaTaskList(AimaTask aimaTask);
|
||||||
|
List<AimaTaskVo> selectAimaTaskVoList(AimaTask aimaTask);
|
||||||
|
int insertAimaTask(AimaTask aimaTask);
|
||||||
|
int updateAimaTask(AimaTask aimaTask);
|
||||||
|
int deleteAimaTaskByIds(String[] ids);
|
||||||
|
int deleteAimaTaskById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为任务绑定测试用例
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @param testCaseIds 测试用例ID列表
|
||||||
|
*/
|
||||||
|
void bindTestCases(String taskId, List<String> testCaseIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取任务的测试用例列表
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 测试用例ID列表
|
||||||
|
*/
|
||||||
|
List<AimaTestCase> getTestCaseIds(String taskId);
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
package com.cmvr.aima.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.cmvr.aima.domain.AimaTestCase;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTestCaseVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛测试用例Service接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface IAimaTestCaseService {
|
||||||
|
/**
|
||||||
|
* 查询爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param id 爱玛测试用例主键
|
||||||
|
* @return 爱玛测试用例
|
||||||
|
*/
|
||||||
|
AimaTestCase selectAimaTestCaseById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛测试用例列表
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 爱玛测试用例集合
|
||||||
|
*/
|
||||||
|
List<AimaTestCase> selectAimaTestCaseList(AimaTestCase aimaTestCase);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛测试用例视图列表(包含关联信息)
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 爱玛测试用例视图集合
|
||||||
|
*/
|
||||||
|
List<AimaTestCaseVo> selectAimaTestCaseVoList(AimaTestCase aimaTestCase);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertAimaTestCase(AimaTestCase aimaTestCase);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateAimaTestCase(AimaTestCase aimaTestCase);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的爱玛测试用例主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaTestCaseByIds(String[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛测试用例信息
|
||||||
|
*
|
||||||
|
* @param id 爱玛测试用例主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaTestCaseById(String id);
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.cmvr.aima.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.cmvr.aima.domain.AimaTestLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛测试日志Service接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface IAimaTestLogService {
|
||||||
|
AimaTestLog selectAimaTestLogById(String id);
|
||||||
|
List<AimaTestLog> selectAimaTestLogList(AimaTestLog aimaTestLog);
|
||||||
|
int insertAimaTestLog(AimaTestLog aimaTestLog);
|
||||||
|
int updateAimaTestLog(AimaTestLog aimaTestLog);
|
||||||
|
int deleteAimaTestLogByIds(String[] ids);
|
||||||
|
int deleteAimaTestLogById(String id);
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package com.cmvr.aima.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.cmvr.aima.domain.AimaVehicle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛车辆管理Service接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
public interface IAimaVehicleService {
|
||||||
|
/**
|
||||||
|
* 查询爱玛车辆管理
|
||||||
|
*
|
||||||
|
* @param id 爱玛车辆管理主键
|
||||||
|
* @return 爱玛车辆管理
|
||||||
|
*/
|
||||||
|
AimaVehicle selectAimaVehicleById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛车辆管理列表
|
||||||
|
*
|
||||||
|
* @param aimaVehicle 爱玛车辆管理
|
||||||
|
* @return 爱玛车辆管理集合
|
||||||
|
*/
|
||||||
|
List<AimaVehicle> selectAimaVehicleList(AimaVehicle aimaVehicle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛车辆管理
|
||||||
|
*
|
||||||
|
* @param aimaVehicle 爱玛车辆管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertAimaVehicle(AimaVehicle aimaVehicle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛车辆管理
|
||||||
|
*
|
||||||
|
* @param aimaVehicle 爱玛车辆管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateAimaVehicle(AimaVehicle aimaVehicle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛车辆管理
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的爱玛车辆管理主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaVehicleByIds(String[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛车辆管理信息
|
||||||
|
*
|
||||||
|
* @param id 爱玛车辆管理主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteAimaVehicleById(String id);
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
package com.cmvr.aima.service.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.cmvr.common.utils.DateUtils;
|
||||||
|
import com.cmvr.common.utils.SecurityUtils;
|
||||||
|
import com.cmvr.aima.mapper.AimaAlarmMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaAlarm;
|
||||||
|
import com.cmvr.aima.service.IAimaAlarmService;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛告警管理Service业务层处理
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class AimaAlarmServiceImpl extends ServiceImpl<AimaAlarmMapper, AimaAlarm> implements IAimaAlarmService {
|
||||||
|
@Autowired
|
||||||
|
private AimaAlarmMapper aimaAlarmMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AimaAlarm selectAimaAlarmById(String id) {
|
||||||
|
return aimaAlarmMapper.selectAimaAlarmById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AimaAlarm> selectAimaAlarmList(AimaAlarm aimaAlarm) {
|
||||||
|
return aimaAlarmMapper.selectAimaAlarmList(aimaAlarm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertAimaAlarm(AimaAlarm aimaAlarm) {
|
||||||
|
if (aimaAlarm.getId() == null || aimaAlarm.getId().isEmpty()) {
|
||||||
|
aimaAlarm.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||||
|
}
|
||||||
|
aimaAlarm.setCreateTime(DateUtils.getNowDate());
|
||||||
|
aimaAlarm.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
return aimaAlarmMapper.insertAimaAlarm(aimaAlarm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateAimaAlarm(AimaAlarm aimaAlarm) {
|
||||||
|
aimaAlarm.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
aimaAlarm.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
return aimaAlarmMapper.updateAimaAlarm(aimaAlarm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteAimaAlarmByIds(String[] ids) {
|
||||||
|
return aimaAlarmMapper.deleteAimaAlarmByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteAimaAlarmById(String id) {
|
||||||
|
return aimaAlarmMapper.deleteAimaAlarmById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,100 @@
|
|||||||
|
package com.cmvr.aima.service.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.cmvr.common.utils.DateUtils;
|
||||||
|
import com.cmvr.common.utils.SecurityUtils;
|
||||||
|
import com.cmvr.aima.mapper.AimaPhoneMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaPhone;
|
||||||
|
import com.cmvr.aima.service.IAimaPhoneService;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛手机管理Service业务层处理
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class AimaPhoneServiceImpl extends ServiceImpl<AimaPhoneMapper, AimaPhone> implements IAimaPhoneService {
|
||||||
|
@Autowired
|
||||||
|
private AimaPhoneMapper aimaPhoneMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param id 爱玛手机管理主键
|
||||||
|
* @return 爱玛手机管理
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AimaPhone selectAimaPhoneById(String id) {
|
||||||
|
return aimaPhoneMapper.selectAimaPhoneById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛手机管理列表
|
||||||
|
*
|
||||||
|
* @param aimaPhone 爱玛手机管理
|
||||||
|
* @return 爱玛手机管理
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<AimaPhone> selectAimaPhoneList(AimaPhone aimaPhone) {
|
||||||
|
return aimaPhoneMapper.selectAimaPhoneList(aimaPhone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param aimaPhone 爱玛手机管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int insertAimaPhone(AimaPhone aimaPhone) {
|
||||||
|
// 生成UUID作为主键
|
||||||
|
if (aimaPhone.getId() == null || aimaPhone.getId().isEmpty()) {
|
||||||
|
aimaPhone.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||||
|
}
|
||||||
|
aimaPhone.setCreateTime(DateUtils.getNowDate());
|
||||||
|
aimaPhone.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
return aimaPhoneMapper.insertAimaPhone(aimaPhone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param aimaPhone 爱玛手机管理
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int updateAimaPhone(AimaPhone aimaPhone) {
|
||||||
|
aimaPhone.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
aimaPhone.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
return aimaPhoneMapper.updateAimaPhone(aimaPhone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛手机管理
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的爱玛手机管理主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int deleteAimaPhoneByIds(String[] ids) {
|
||||||
|
return aimaPhoneMapper.deleteAimaPhoneByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛手机管理信息
|
||||||
|
*
|
||||||
|
* @param id 爱玛手机管理主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int deleteAimaPhoneById(String id) {
|
||||||
|
return aimaPhoneMapper.deleteAimaPhoneById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,234 @@
|
|||||||
|
package com.cmvr.aima.service.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.cmvr.aima.domain.dto.AimaTaskInstanceQuery;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTaskInstanceVo;
|
||||||
|
import com.cmvr.common.exception.ServiceException;
|
||||||
|
import com.cmvr.common.utils.SecurityUtils;
|
||||||
|
import com.cmvr.test.flow.control.FlowControlService;
|
||||||
|
import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService;
|
||||||
|
import com.cmvr.test.flow.runtime.event.FlowExecutionModuleCodes;
|
||||||
|
import com.cmvr.test.model.vo.TeTaskExecuteNormalVO;
|
||||||
|
import com.cmvr.test.service.ITeTaskOrchestrationService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.cmvr.common.utils.DateUtils;
|
||||||
|
import com.cmvr.aima.mapper.AimaTaskInstanceMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaTaskInstance;
|
||||||
|
import com.cmvr.aima.service.IAimaTaskInstanceService;
|
||||||
|
import com.cmvr.aima.enums.AimaTaskStatusEnum;
|
||||||
|
import com.cmvr.aima.service.IAimaTaskService;
|
||||||
|
import com.cmvr.aima.domain.AimaTask;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛任务执行实例Service业务层处理
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class AimaTaskInstanceServiceImpl extends ServiceImpl<AimaTaskInstanceMapper, AimaTaskInstance> implements IAimaTaskInstanceService {
|
||||||
|
@Autowired
|
||||||
|
private AimaTaskInstanceMapper aimaTaskInstanceMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IAimaTaskService aimaTaskService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ITeTaskOrchestrationService teTaskOrchestrationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Lazy
|
||||||
|
private FlowTaskRuntimeService flowTaskRuntimeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Lazy
|
||||||
|
private FlowControlService flowControlService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AimaTaskInstance selectAimaTaskInstanceById(String id) {
|
||||||
|
return aimaTaskInstanceMapper.selectAimaTaskInstanceById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AimaTaskInstance> selectAimaTaskInstanceList(AimaTaskInstance aimaTaskInstance) {
|
||||||
|
return aimaTaskInstanceMapper.selectAimaTaskInstanceList(aimaTaskInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AimaTaskInstanceVo> selectAimaTaskInstanceVoList(AimaTaskInstanceQuery query) {
|
||||||
|
return aimaTaskInstanceMapper.selectAimaTaskInstanceVoList(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertAimaTaskInstance(AimaTaskInstance aimaTaskInstance) {
|
||||||
|
if (aimaTaskInstance.getId() == null || aimaTaskInstance.getId().isEmpty()) {
|
||||||
|
aimaTaskInstance.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||||
|
}
|
||||||
|
aimaTaskInstance.setStatus(AimaTaskStatusEnum.NOT_STARTED.getCode());
|
||||||
|
aimaTaskInstance.setCreateTime(DateUtils.getNowDate());
|
||||||
|
aimaTaskInstance.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
// 获取测试用例数量
|
||||||
|
AimaTask aimaTask = aimaTaskService.selectAimaTaskById(aimaTaskInstance.getTaskId());
|
||||||
|
if (aimaTask != null && aimaTask.getTestCaseCount() != null) {
|
||||||
|
aimaTaskInstance.setTotalCases(aimaTask.getTestCaseCount());
|
||||||
|
}
|
||||||
|
return aimaTaskInstanceMapper.insertAimaTaskInstance(aimaTaskInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateAimaTaskInstance(AimaTaskInstance aimaTaskInstance) {
|
||||||
|
// 校验状态,只有未执行可以修改
|
||||||
|
if (AimaTaskStatusEnum.NOT_STARTED.getCode() != aimaTaskInstance.getStatus()) {
|
||||||
|
throw new ServiceException("只有未执行状态的任务实例才能修改");
|
||||||
|
}
|
||||||
|
aimaTaskInstance.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
aimaTaskInstance.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
// 获取测试用例数量
|
||||||
|
AimaTask aimaTask = aimaTaskService.selectAimaTaskById(aimaTaskInstance.getTaskId());
|
||||||
|
if (aimaTask != null && aimaTask.getTestCaseCount() != null) {
|
||||||
|
aimaTaskInstance.setTotalCases(aimaTask.getTestCaseCount());
|
||||||
|
}
|
||||||
|
return aimaTaskInstanceMapper.updateAimaTaskInstance(aimaTaskInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteAimaTaskInstanceByIds(String[] ids) {
|
||||||
|
// 校验状态,只有未执行可以删除
|
||||||
|
for (String id : ids) {
|
||||||
|
AimaTaskInstance instance = aimaTaskInstanceMapper.selectAimaTaskInstanceById(id);
|
||||||
|
if (instance != null && AimaTaskStatusEnum.NOT_STARTED.getCode() != instance.getStatus()) {
|
||||||
|
throw new ServiceException("只有未执行状态的任务实例才能删除");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aimaTaskInstanceMapper.deleteAimaTaskInstanceByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteAimaTaskInstanceById(String id) {
|
||||||
|
return aimaTaskInstanceMapper.deleteAimaTaskInstanceById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始执行任务实例
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int startInstance(String id) {
|
||||||
|
AimaTaskInstance instance = aimaTaskInstanceMapper.selectAimaTaskInstanceById(id);
|
||||||
|
if (instance == null) {
|
||||||
|
throw new ServiceException("任务实例不存在");
|
||||||
|
}
|
||||||
|
if (AimaTaskStatusEnum.NOT_STARTED.getCode() != instance.getStatus()) {
|
||||||
|
throw new ServiceException("只有待执行状态的任务实例才能开始执行");
|
||||||
|
}
|
||||||
|
AimaTaskInstance update = new AimaTaskInstance();
|
||||||
|
update.setId(id);
|
||||||
|
update.setStatus(AimaTaskStatusEnum.RUNNING.getCode());
|
||||||
|
update.setStartTime(DateUtils.getNowDate());
|
||||||
|
update.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
update.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AimaTask aimaTask = aimaTaskService.selectAimaTaskById(instance.getTaskId());
|
||||||
|
JSONObject runParams = new JSONObject();
|
||||||
|
// 从test模块的任务编排中获取所有的检测项id
|
||||||
|
if (aimaTask != null && aimaTask.getTaskConfigId() != null) {
|
||||||
|
teTaskOrchestrationService.queryByTaskId(aimaTask.getTaskConfigId())
|
||||||
|
.forEach(item -> runParams.put(item.getItemId(), new JSONObject()));
|
||||||
|
}
|
||||||
|
// 调用流程引擎执行
|
||||||
|
String insId = flowTaskRuntimeService.executeTask(
|
||||||
|
TeTaskExecuteNormalVO.builder()
|
||||||
|
.taskId(aimaTask.getTaskConfigId())
|
||||||
|
.moduleCode(FlowExecutionModuleCodes.AIMA)
|
||||||
|
.runParams(runParams)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
update.setTaskInsId(insId);
|
||||||
|
return aimaTaskInstanceMapper.updateAimaTaskInstance(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停任务实例
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int pauseInstance(String id) {
|
||||||
|
AimaTaskInstance instance = aimaTaskInstanceMapper.selectAimaTaskInstanceById(id);
|
||||||
|
if (instance == null) {
|
||||||
|
throw new ServiceException("任务实例不存在");
|
||||||
|
}
|
||||||
|
if (AimaTaskStatusEnum.RUNNING.getCode() != instance.getStatus()) {
|
||||||
|
throw new ServiceException("只有执行中状态的任务实例才能暂停");
|
||||||
|
}
|
||||||
|
AimaTaskInstance update = new AimaTaskInstance();
|
||||||
|
update.setId(id);
|
||||||
|
update.setStatus(AimaTaskStatusEnum.PAUSED.getCode());
|
||||||
|
update.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
update.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
flowControlService.pause(instance.getTaskInsId());
|
||||||
|
return aimaTaskInstanceMapper.updateAimaTaskInstance(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终止任务实例
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int stopInstance(String id) {
|
||||||
|
AimaTaskInstance instance = aimaTaskInstanceMapper.selectAimaTaskInstanceById(id);
|
||||||
|
if (instance == null) {
|
||||||
|
throw new ServiceException("任务实例不存在");
|
||||||
|
}
|
||||||
|
if (AimaTaskStatusEnum.NOT_STARTED.getCode() != instance.getStatus()
|
||||||
|
&& AimaTaskStatusEnum.RUNNING.getCode() != instance.getStatus()) {
|
||||||
|
throw new ServiceException("已完成或已取消的任务实例不能终止");
|
||||||
|
}
|
||||||
|
AimaTaskInstance update = new AimaTaskInstance();
|
||||||
|
update.setId(id);
|
||||||
|
update.setStatus(AimaTaskStatusEnum.STOPPED.getCode());
|
||||||
|
update.setEndTime(DateUtils.getNowDate());
|
||||||
|
update.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
update.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
flowControlService.stop(instance.getTaskInsId());
|
||||||
|
return aimaTaskInstanceMapper.updateAimaTaskInstance(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复任务实例(从暂停恢复为执行中)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int resumeInstance(String id) {
|
||||||
|
AimaTaskInstance instance = aimaTaskInstanceMapper.selectAimaTaskInstanceById(id);
|
||||||
|
if (instance == null) {
|
||||||
|
throw new ServiceException("任务实例不存在");
|
||||||
|
}
|
||||||
|
if (AimaTaskStatusEnum.PAUSED.getCode() != instance.getStatus()) {
|
||||||
|
throw new ServiceException("只有已暂停状态的任务实例才能恢复");
|
||||||
|
}
|
||||||
|
AimaTaskInstance update = new AimaTaskInstance();
|
||||||
|
update.setId(id);
|
||||||
|
update.setStatus(AimaTaskStatusEnum.RUNNING.getCode());
|
||||||
|
update.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
update.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
flowControlService.resume(instance.getTaskInsId());
|
||||||
|
return aimaTaskInstanceMapper.updateAimaTaskInstance(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新任务实例进度
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateProgress(String instanceId, Double progress) {
|
||||||
|
AimaTaskInstance update = new AimaTaskInstance();
|
||||||
|
update.setId(instanceId);
|
||||||
|
update.setProgress(progress);
|
||||||
|
update.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
aimaTaskInstanceMapper.updateAimaTaskInstance(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,159 @@
|
|||||||
|
package com.cmvr.aima.service.impl;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.cmvr.aima.domain.AimaTaskTestCase;
|
||||||
|
import com.cmvr.aima.domain.AimaTestCase;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTaskVo;
|
||||||
|
import com.cmvr.aima.mapper.AimaTestCaseMapper;
|
||||||
|
import com.cmvr.test.model.domain.TeTaskConfigInfo;
|
||||||
|
import com.cmvr.test.model.vo.TeTaskOrchestraVO;
|
||||||
|
import com.cmvr.test.service.ITeTaskConfigInfoService;
|
||||||
|
import com.cmvr.test.service.ITeTaskOrchestrationService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.cmvr.common.utils.DateUtils;
|
||||||
|
import com.cmvr.common.utils.SecurityUtils;
|
||||||
|
import com.cmvr.aima.mapper.AimaTaskMapper;
|
||||||
|
import com.cmvr.aima.mapper.AimaTaskTestCaseMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaTask;
|
||||||
|
import com.cmvr.aima.service.IAimaTaskService;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class AimaTaskServiceImpl extends ServiceImpl<AimaTaskMapper, AimaTask> implements IAimaTaskService {
|
||||||
|
@Autowired
|
||||||
|
private AimaTaskMapper aimaTaskMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AimaTaskTestCaseMapper aimaTaskTestCaseMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AimaTestCaseMapper aimaTestCaseMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ITeTaskOrchestrationService teTaskOrchestrationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ITeTaskConfigInfoService teTaskConfigInfoService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AimaTask selectAimaTaskById(String id) {
|
||||||
|
return aimaTaskMapper.selectAimaTaskById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AimaTask> selectAimaTaskList(AimaTask aimaTask) {
|
||||||
|
return aimaTaskMapper.selectAimaTaskList(aimaTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AimaTaskVo> selectAimaTaskVoList(AimaTask aimaTask) {
|
||||||
|
return aimaTaskMapper.selectAimaTaskVoList(aimaTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertAimaTask(AimaTask aimaTask) {
|
||||||
|
// 生成UUID作为主键
|
||||||
|
if (aimaTask.getId() == null || aimaTask.getId().isEmpty()) {
|
||||||
|
aimaTask.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||||
|
}
|
||||||
|
aimaTask.setCreateTime(DateUtils.getNowDate());
|
||||||
|
aimaTask.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
// 同步新增任务配置到test模块
|
||||||
|
TeTaskConfigInfo teTaskConfigInfo = TeTaskConfigInfo.builder()
|
||||||
|
.taskName(aimaTask.getTaskName())
|
||||||
|
.build();
|
||||||
|
teTaskConfigInfoService.insertTeTaskConfigInfo(teTaskConfigInfo);
|
||||||
|
aimaTask.setTaskConfigId(teTaskConfigInfo.getId());
|
||||||
|
return aimaTaskMapper.insertAimaTask(aimaTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateAimaTask(AimaTask aimaTask) {
|
||||||
|
aimaTask.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
aimaTask.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
// 同步更新任务配置名称
|
||||||
|
if (aimaTask.getTaskConfigId() != null) {
|
||||||
|
TeTaskConfigInfo teTaskConfigInfo = teTaskConfigInfoService.selectTeTaskConfigInfoById(aimaTask.getTaskConfigId());
|
||||||
|
if (teTaskConfigInfo != null) {
|
||||||
|
teTaskConfigInfo.setTaskName(aimaTask.getTaskName());
|
||||||
|
teTaskConfigInfoService.updateTeTaskConfigInfo(teTaskConfigInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aimaTaskMapper.updateAimaTask(aimaTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteAimaTaskByIds(String[] ids) {
|
||||||
|
// 先删除关联表数据
|
||||||
|
aimaTaskTestCaseMapper.deleteTaskTestCaseByTaskIds(ids);
|
||||||
|
// 批量查询任务
|
||||||
|
List<AimaTask> aimaTasks = this.baseMapper.selectBatchIds(Arrays.asList(ids));
|
||||||
|
// 批量删除任务配置
|
||||||
|
teTaskConfigInfoService.deleteTeTaskConfigInfoByIds(
|
||||||
|
aimaTasks.stream().map(AimaTask::getTaskConfigId).toArray(String[]::new)
|
||||||
|
);
|
||||||
|
return aimaTaskMapper.deleteAimaTaskByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteAimaTaskById(String id) {
|
||||||
|
return aimaTaskMapper.deleteAimaTaskById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindTestCases(String taskId, List<String> testCaseIds) {
|
||||||
|
// 先删除旧的关联
|
||||||
|
aimaTaskTestCaseMapper.deleteTaskTestCaseByTaskId(taskId);
|
||||||
|
|
||||||
|
// 批量插入新的关联
|
||||||
|
if (testCaseIds != null && !testCaseIds.isEmpty()) {
|
||||||
|
List<AimaTaskTestCase> list = new ArrayList<>();
|
||||||
|
for (int i = 0; i < testCaseIds.size(); i++) {
|
||||||
|
AimaTaskTestCase taskTestCase = new AimaTaskTestCase();
|
||||||
|
taskTestCase.setTaskId(taskId);
|
||||||
|
taskTestCase.setTestCaseId(testCaseIds.get(i));
|
||||||
|
taskTestCase.setSortOrder(i);
|
||||||
|
list.add(taskTestCase);
|
||||||
|
}
|
||||||
|
aimaTaskTestCaseMapper.batchInsertTaskTestCase(list);
|
||||||
|
|
||||||
|
// 更新任务的测试用例数量
|
||||||
|
AimaTask task = new AimaTask();
|
||||||
|
task.setId(taskId);
|
||||||
|
task.setTestCaseCount(testCaseIds.size());
|
||||||
|
aimaTaskMapper.updateAimaTask(task);
|
||||||
|
|
||||||
|
// 查询测试用例,获取detectItemId列表
|
||||||
|
List<AimaTestCase> testCases = aimaTestCaseMapper.selectBatchIds(testCaseIds);
|
||||||
|
List<String> detectItemIds = testCases.stream()
|
||||||
|
.map(AimaTestCase::getDetectItemId)
|
||||||
|
.filter(itemId -> itemId != null && !itemId.isEmpty())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 同步任务编排到test模块
|
||||||
|
if (!detectItemIds.isEmpty()) {
|
||||||
|
AimaTask aimaTask = aimaTaskMapper.selectAimaTaskById(taskId);
|
||||||
|
TeTaskOrchestraVO teTaskOrchestraVO = TeTaskOrchestraVO.builder()
|
||||||
|
.taskId(aimaTask.getTaskConfigId())
|
||||||
|
.itemIds(detectItemIds)
|
||||||
|
.build();
|
||||||
|
teTaskOrchestrationService.insertTeTaskOrchestration(teTaskOrchestraVO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AimaTestCase> getTestCaseIds(String taskId) {
|
||||||
|
List<String> ids = aimaTaskTestCaseMapper.selectTestCaseIdsByTaskId(taskId);
|
||||||
|
return aimaTestCaseMapper.selectList(new QueryWrapper<AimaTestCase>().in("id", ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,139 @@
|
|||||||
|
package com.cmvr.aima.service.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.cmvr.aima.domain.vo.AimaTestCaseVo;
|
||||||
|
import com.cmvr.test.model.domain.TeDetectionItem;
|
||||||
|
import com.cmvr.test.service.ITeDetectionItemService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.cmvr.common.utils.DateUtils;
|
||||||
|
import com.cmvr.common.utils.SecurityUtils;
|
||||||
|
import com.cmvr.aima.mapper.AimaTestCaseMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaTestCase;
|
||||||
|
import com.cmvr.aima.service.IAimaTestCaseService;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛测试用例Service业务层处理
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class AimaTestCaseServiceImpl extends ServiceImpl<AimaTestCaseMapper, AimaTestCase> implements IAimaTestCaseService {
|
||||||
|
@Autowired
|
||||||
|
private AimaTestCaseMapper aimaTestCaseMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ITeDetectionItemService teDetectionItemService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param id 爱玛测试用例主键
|
||||||
|
* @return 爱玛测试用例
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AimaTestCase selectAimaTestCaseById(String id) {
|
||||||
|
return aimaTestCaseMapper.selectAimaTestCaseById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛测试用例列表
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 爱玛测试用例
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<AimaTestCase> selectAimaTestCaseList(AimaTestCase aimaTestCase) {
|
||||||
|
return aimaTestCaseMapper.selectAimaTestCaseList(aimaTestCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询爱玛测试用例视图列表(包含关联信息)
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 爱玛测试用例视图集合
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<AimaTestCaseVo> selectAimaTestCaseVoList(AimaTestCase aimaTestCase) {
|
||||||
|
return aimaTestCaseMapper.selectAimaTestCaseVoList(aimaTestCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int insertAimaTestCase(AimaTestCase aimaTestCase) {
|
||||||
|
// 生成UUID作为主键
|
||||||
|
if (aimaTestCase.getId() == null || aimaTestCase.getId().isEmpty()) {
|
||||||
|
aimaTestCase.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||||
|
}
|
||||||
|
aimaTestCase.setCreateTime(DateUtils.getNowDate());
|
||||||
|
aimaTestCase.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
// 同步新增检测项配置到test模块
|
||||||
|
TeDetectionItem teDetectionItem = TeDetectionItem.builder()
|
||||||
|
.detectName(aimaTestCase.getCaseName())
|
||||||
|
.groupId(7L) // 可以根据实际情况调整分组ID
|
||||||
|
.build();
|
||||||
|
teDetectionItemService.insertTeDetectionItem(teDetectionItem);
|
||||||
|
aimaTestCase.setDetectItemId(teDetectionItem.getId());
|
||||||
|
return aimaTestCaseMapper.insertAimaTestCase(aimaTestCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param aimaTestCase 爱玛测试用例
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int updateAimaTestCase(AimaTestCase aimaTestCase) {
|
||||||
|
aimaTestCase.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
aimaTestCase.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
// 同步更新检测项名称
|
||||||
|
if (aimaTestCase.getDetectItemId() != null) {
|
||||||
|
TeDetectionItem teDetectionItem = teDetectionItemService.selectTeDetectionItemById(aimaTestCase.getDetectItemId());
|
||||||
|
if (teDetectionItem != null) {
|
||||||
|
teDetectionItem.setDetectName(aimaTestCase.getCaseName());
|
||||||
|
teDetectionItemService.updateTeDetectionItem(teDetectionItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aimaTestCaseMapper.updateAimaTestCase(aimaTestCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除爱玛测试用例
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的爱玛测试用例主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int deleteAimaTestCaseByIds(String[] ids) {
|
||||||
|
// 先查询数据,删除绑定的检测项
|
||||||
|
for (String id : ids) {
|
||||||
|
AimaTestCase aimaTestCase = aimaTestCaseMapper.selectAimaTestCaseById(id);
|
||||||
|
if (aimaTestCase != null && aimaTestCase.getDetectItemId() != null) {
|
||||||
|
teDetectionItemService.deleteTeDetectionItemById(aimaTestCase.getDetectItemId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aimaTestCaseMapper.deleteAimaTestCaseByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除爱玛测试用例信息
|
||||||
|
*
|
||||||
|
* @param id 爱玛测试用例主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int deleteAimaTestCaseById(String id) {
|
||||||
|
return aimaTestCaseMapper.deleteAimaTestCaseById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package com.cmvr.aima.service.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.cmvr.common.utils.DateUtils;
|
||||||
|
import com.cmvr.common.utils.SecurityUtils;
|
||||||
|
import com.cmvr.aima.mapper.AimaTestLogMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaTestLog;
|
||||||
|
import com.cmvr.aima.service.IAimaTestLogService;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛测试日志Service业务层处理
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class AimaTestLogServiceImpl extends ServiceImpl<AimaTestLogMapper, AimaTestLog> implements IAimaTestLogService {
|
||||||
|
@Autowired
|
||||||
|
private AimaTestLogMapper aimaTestLogMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AimaTestLog selectAimaTestLogById(String id) {
|
||||||
|
return aimaTestLogMapper.selectAimaTestLogById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AimaTestLog> selectAimaTestLogList(AimaTestLog aimaTestLog) {
|
||||||
|
return aimaTestLogMapper.selectAimaTestLogList(aimaTestLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertAimaTestLog(AimaTestLog aimaTestLog) {
|
||||||
|
if (aimaTestLog.getId() == null || aimaTestLog.getId().isEmpty()) {
|
||||||
|
aimaTestLog.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||||
|
}
|
||||||
|
aimaTestLog.setCreateTime(DateUtils.getNowDate());
|
||||||
|
return aimaTestLogMapper.insertAimaTestLog(aimaTestLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateAimaTestLog(AimaTestLog aimaTestLog) {
|
||||||
|
aimaTestLog.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
return aimaTestLogMapper.updateAimaTestLog(aimaTestLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteAimaTestLogByIds(String[] ids) {
|
||||||
|
return aimaTestLogMapper.deleteAimaTestLogByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteAimaTestLogById(String id) {
|
||||||
|
return aimaTestLogMapper.deleteAimaTestLogById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
package com.cmvr.aima.service.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.cmvr.common.utils.DateUtils;
|
||||||
|
import com.cmvr.common.utils.SecurityUtils;
|
||||||
|
import com.cmvr.aima.mapper.AimaVehicleMapper;
|
||||||
|
import com.cmvr.aima.domain.AimaVehicle;
|
||||||
|
import com.cmvr.aima.service.IAimaVehicleService;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爱玛车辆管理Service业务层处理
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-06-22
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class AimaVehicleServiceImpl extends ServiceImpl<AimaVehicleMapper, AimaVehicle> implements IAimaVehicleService {
|
||||||
|
@Autowired
|
||||||
|
private AimaVehicleMapper aimaVehicleMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AimaVehicle selectAimaVehicleById(String id) {
|
||||||
|
return aimaVehicleMapper.selectAimaVehicleById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AimaVehicle> selectAimaVehicleList(AimaVehicle aimaVehicle) {
|
||||||
|
return aimaVehicleMapper.selectAimaVehicleList(aimaVehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertAimaVehicle(AimaVehicle aimaVehicle) {
|
||||||
|
if (aimaVehicle.getId() == null || aimaVehicle.getId().isEmpty()) {
|
||||||
|
aimaVehicle.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||||
|
}
|
||||||
|
aimaVehicle.setCreateTime(DateUtils.getNowDate());
|
||||||
|
aimaVehicle.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
return aimaVehicleMapper.insertAimaVehicle(aimaVehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateAimaVehicle(AimaVehicle aimaVehicle) {
|
||||||
|
aimaVehicle.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
aimaVehicle.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
return aimaVehicleMapper.updateAimaVehicle(aimaVehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteAimaVehicleByIds(String[] ids) {
|
||||||
|
return aimaVehicleMapper.deleteAimaVehicleByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteAimaVehicleById(String id) {
|
||||||
|
return aimaVehicleMapper.deleteAimaVehicleById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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.cmvr.aima.mapper.AimaAlarmMapper">
|
||||||
|
<resultMap type="AimaAlarm" id="AimaAlarmResult">
|
||||||
|
<result property="id" column="id"/><result property="createBy" column="create_by"/><result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/><result property="updateTime" column="update_time"/><result property="remark" column="remark"/>
|
||||||
|
<result property="alarmCode" column="alarm_code"/><result property="taskInstanceId" column="task_instance_id"/><result property="taskId" column="task_id"/>
|
||||||
|
<result property="taskName" column="task_name"/><result property="phoneId" column="phone_id"/><result property="phoneName" column="phone_name"/>
|
||||||
|
<result property="vehicleId" column="vehicle_id"/><result property="vin" column="vin"/><result property="testCaseId" column="test_case_id"/>
|
||||||
|
<result property="caseName" column="case_name"/><result property="alarmLevel" column="alarm_level"/><result property="alarmType" column="alarm_type"/>
|
||||||
|
<result property="alarmTitle" column="alarm_title"/><result property="alarmContent" column="alarm_content"/><result property="alarmLocation" column="alarm_location"/>
|
||||||
|
<result property="alarmTime" column="alarm_time"/><result property="handleStatus" column="handle_status"/><result property="handler" column="handler"/>
|
||||||
|
<result property="handleTime" column="handle_time"/><result property="handleRemark" column="handle_remark"/><result property="evidenceImage" column="evidence_image"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectAimaAlarmVo">
|
||||||
|
select id, create_by, create_time, update_by, update_time, remark, alarm_code, task_instance_id, task_id, task_name, phone_id, phone_name, vehicle_id, vin, test_case_id, case_name, alarm_level, alarm_type, alarm_title, alarm_content, alarm_location, alarm_time, handle_status, handler, handle_time, handle_remark, evidence_image from aima_alarm
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectAimaAlarmList" parameterType="AimaAlarm" resultMap="AimaAlarmResult">
|
||||||
|
<include refid="selectAimaAlarmVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="alarmCode != null and alarmCode != ''"> and alarm_code = #{alarmCode}</if>
|
||||||
|
<if test="taskInstanceId != null and taskInstanceId != ''"> and task_instance_id = #{taskInstanceId}</if>
|
||||||
|
<if test="taskId != null and taskId != ''"> and task_id = #{taskId}</if>
|
||||||
|
<if test="alarmLevel != null and alarmLevel != ''"> and alarm_level = #{alarmLevel}</if>
|
||||||
|
<if test="alarmType != null and alarmType != ''"> and alarm_type = #{alarmType}</if>
|
||||||
|
<if test="handleStatus != null and handleStatus != ''"> and handle_status = #{handleStatus}</if>
|
||||||
|
</where>
|
||||||
|
order by alarm_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAimaAlarmById" parameterType="String" resultMap="AimaAlarmResult">
|
||||||
|
<include refid="selectAimaAlarmVo"/> where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertAimaAlarm" parameterType="AimaAlarm">
|
||||||
|
insert into aima_alarm <trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">id,</if><if test="createBy != null">create_by,</if><if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if><if test="updateTime != null">update_time,</if><if test="remark != null">remark,</if>
|
||||||
|
<if test="alarmCode != null">alarm_code,</if><if test="taskInstanceId != null">task_instance_id,</if><if test="taskId != null">task_id,</if>
|
||||||
|
<if test="taskName != null">task_name,</if><if test="phoneId != null">phone_id,</if><if test="phoneName != null">phone_name,</if>
|
||||||
|
<if test="vehicleId != null">vehicle_id,</if><if test="vin != null">vin,</if><if test="testCaseId != null">test_case_id,</if>
|
||||||
|
<if test="caseName != null">case_name,</if><if test="alarmLevel != null">alarm_level,</if><if test="alarmType != null">alarm_type,</if>
|
||||||
|
<if test="alarmTitle != null">alarm_title,</if><if test="alarmContent != null">alarm_content,</if><if test="alarmLocation != null">alarm_location,</if>
|
||||||
|
<if test="alarmTime != null">alarm_time,</if><if test="handleStatus != null">handle_status,</if><if test="handler != null">handler,</if>
|
||||||
|
<if test="handleTime != null">handle_time,</if><if test="handleRemark != null">handle_remark,</if><if test="evidenceImage != null">evidence_image,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">#{id},</if><if test="createBy != null">#{createBy},</if><if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if><if test="updateTime != null">#{updateTime},</if><if test="remark != null">#{remark},</if>
|
||||||
|
<if test="alarmCode != null">#{alarmCode},</if><if test="taskInstanceId != null">#{taskInstanceId},</if><if test="taskId != null">#{taskId},</if>
|
||||||
|
<if test="taskName != null">#{taskName},</if><if test="phoneId != null">#{phoneId},</if><if test="phoneName != null">#{phoneName},</if>
|
||||||
|
<if test="vehicleId != null">#{vehicleId},</if><if test="vin != null">#{vin},</if><if test="testCaseId != null">#{testCaseId},</if>
|
||||||
|
<if test="caseName != null">#{caseName},</if><if test="alarmLevel != null">#{alarmLevel},</if><if test="alarmType != null">#{alarmType},</if>
|
||||||
|
<if test="alarmTitle != null">#{alarmTitle},</if><if test="alarmContent != null">#{alarmContent},</if><if test="alarmLocation != null">#{alarmLocation},</if>
|
||||||
|
<if test="alarmTime != null">#{alarmTime},</if><if test="handleStatus != null">#{handleStatus},</if><if test="handler != null">#{handler},</if>
|
||||||
|
<if test="handleTime != null">#{handleTime},</if><if test="handleRemark != null">#{handleRemark},</if><if test="evidenceImage != null">#{evidenceImage},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateAimaAlarm" parameterType="AimaAlarm">
|
||||||
|
update aima_alarm <trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="createBy != null">create_by = #{createBy},</if><if test="createTime != null">create_time = #{createTime},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if><if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if><if test="alarmCode != null">alarm_code = #{alarmCode},</if>
|
||||||
|
<if test="taskInstanceId != null">task_instance_id = #{taskInstanceId},</if><if test="taskId != null">task_id = #{taskId},</if>
|
||||||
|
<if test="taskName != null">task_name = #{taskName},</if><if test="phoneId != null">phone_id = #{phoneId},</if>
|
||||||
|
<if test="phoneName != null">phone_name = #{phoneName},</if><if test="vehicleId != null">vehicle_id = #{vehicleId},</if>
|
||||||
|
<if test="vin != null">vin = #{vin},</if><if test="testCaseId != null">test_case_id = #{testCaseId},</if>
|
||||||
|
<if test="caseName != null">case_name = #{caseName},</if><if test="alarmLevel != null">alarm_level = #{alarmLevel},</if>
|
||||||
|
<if test="alarmType != null">alarm_type = #{alarmType},</if><if test="alarmTitle != null">alarm_title = #{alarmTitle},</if>
|
||||||
|
<if test="alarmContent != null">alarm_content = #{alarmContent},</if><if test="alarmLocation != null">alarm_location = #{alarmLocation},</if>
|
||||||
|
<if test="alarmTime != null">alarm_time = #{alarmTime},</if><if test="handleStatus != null">handle_status = #{handleStatus},</if>
|
||||||
|
<if test="handler != null">handler = #{handler},</if><if test="handleTime != null">handle_time = #{handleTime},</if>
|
||||||
|
<if test="handleRemark != null">handle_remark = #{handleRemark},</if><if test="evidenceImage != null">evidence_image = #{evidenceImage},</if>
|
||||||
|
</trim> where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteAimaAlarmById" parameterType="String">delete from aima_alarm where id = #{id}</delete>
|
||||||
|
<delete id="deleteAimaAlarmByIds" parameterType="String">
|
||||||
|
delete from aima_alarm where id in <foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach>
|
||||||
|
</delete>
|
||||||
|
</mapper>
|
||||||
106
cmvr-iot-aima/src/main/resources/mapper/aima/AimaPhoneMapper.xml
Normal file
106
cmvr-iot-aima/src/main/resources/mapper/aima/AimaPhoneMapper.xml
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<?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.cmvr.aima.mapper.AimaPhoneMapper">
|
||||||
|
|
||||||
|
<resultMap type="AimaPhone" id="AimaPhoneResult">
|
||||||
|
<result property="id" column="id" />
|
||||||
|
<result property="createBy" column="create_by" />
|
||||||
|
<result property="createTime" column="create_time" />
|
||||||
|
<result property="updateBy" column="update_by" />
|
||||||
|
<result property="updateTime" column="update_time" />
|
||||||
|
<result property="remark" column="remark" />
|
||||||
|
<result property="phoneName" column="phone_name" />
|
||||||
|
<result property="phoneModel" column="phone_model" />
|
||||||
|
<result property="osSystem" column="os_system" />
|
||||||
|
<result property="osVersion" column="os_version" />
|
||||||
|
<result property="specifications" column="specifications" />
|
||||||
|
<result property="manufacturer" column="manufacturer" />
|
||||||
|
<result property="status" column="status" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectAimaPhoneVo">
|
||||||
|
select id, create_by, create_time, update_by, update_time, remark, phone_name, phone_model, os_system, os_version, specifications, manufacturer, status from aima_phone
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectAimaPhoneList" parameterType="AimaPhone" resultMap="AimaPhoneResult">
|
||||||
|
<include refid="selectAimaPhoneVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="phoneName != null and phoneName != ''"> and phone_name like concat('%', #{phoneName}, '%')</if>
|
||||||
|
<if test="phoneModel != null and phoneModel != ''"> and phone_model like concat('%', #{phoneModel}, '%')</if>
|
||||||
|
<if test="osSystem != null and osSystem != ''"> and os_system = #{osSystem}</if>
|
||||||
|
<if test="status != null and status != ''"> and status = #{status}</if>
|
||||||
|
</where>
|
||||||
|
order by create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAimaPhoneById" parameterType="String" resultMap="AimaPhoneResult">
|
||||||
|
<include refid="selectAimaPhoneVo"/>
|
||||||
|
where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertAimaPhone" parameterType="AimaPhone">
|
||||||
|
insert into aima_phone
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">id,</if>
|
||||||
|
<if test="createBy != null">create_by,</if>
|
||||||
|
<if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if>
|
||||||
|
<if test="updateTime != null">update_time,</if>
|
||||||
|
<if test="remark != null">remark,</if>
|
||||||
|
<if test="phoneName != null">phone_name,</if>
|
||||||
|
<if test="phoneModel != null">phone_model,</if>
|
||||||
|
<if test="osSystem != null">os_system,</if>
|
||||||
|
<if test="osVersion != null">os_version,</if>
|
||||||
|
<if test="specifications != null">specifications,</if>
|
||||||
|
<if test="manufacturer != null">manufacturer,</if>
|
||||||
|
<if test="status != null">status,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">#{id},</if>
|
||||||
|
<if test="createBy != null">#{createBy},</if>
|
||||||
|
<if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if>
|
||||||
|
<if test="updateTime != null">#{updateTime},</if>
|
||||||
|
<if test="remark != null">#{remark},</if>
|
||||||
|
<if test="phoneName != null">#{phoneName},</if>
|
||||||
|
<if test="phoneModel != null">#{phoneModel},</if>
|
||||||
|
<if test="osSystem != null">#{osSystem},</if>
|
||||||
|
<if test="osVersion != null">#{osVersion},</if>
|
||||||
|
<if test="specifications != null">#{specifications},</if>
|
||||||
|
<if test="manufacturer != null">#{manufacturer},</if>
|
||||||
|
<if test="status != null">#{status},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateAimaPhone" parameterType="AimaPhone">
|
||||||
|
update aima_phone
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="createBy != null">create_by = #{createBy},</if>
|
||||||
|
<if test="createTime != null">create_time = #{createTime},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||||
|
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
<if test="phoneName != null">phone_name = #{phoneName},</if>
|
||||||
|
<if test="phoneModel != null">phone_model = #{phoneModel},</if>
|
||||||
|
<if test="osSystem != null">os_system = #{osSystem},</if>
|
||||||
|
<if test="osVersion != null">os_version = #{osVersion},</if>
|
||||||
|
<if test="specifications != null">specifications = #{specifications},</if>
|
||||||
|
<if test="manufacturer != null">manufacturer = #{manufacturer},</if>
|
||||||
|
<if test="status != null">status = #{status},</if>
|
||||||
|
</trim>
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteAimaPhoneById" parameterType="String">
|
||||||
|
delete from aima_phone where id = #{id}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<delete id="deleteAimaPhoneByIds" parameterType="String">
|
||||||
|
delete from aima_phone where id in
|
||||||
|
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
</mapper>
|
||||||
@ -0,0 +1,122 @@
|
|||||||
|
<?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.cmvr.aima.mapper.AimaTaskInstanceMapper">
|
||||||
|
<resultMap type="AimaTaskInstance" id="AimaTaskInstanceResult">
|
||||||
|
<result property="id" column="id"/><result property="createBy" column="create_by"/><result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/><result property="updateTime" column="update_time"/><result property="remark" column="remark"/>
|
||||||
|
<result property="taskId" column="task_id"/><result property="phoneId" column="phone_id"/>
|
||||||
|
<result property="vehicleId" column="vehicle_id"/>
|
||||||
|
<result property="executionNumber" column="execution_number"/><result property="status" column="status"/><result property="taskInsId" column="task_ins_id"/>
|
||||||
|
<result property="totalCases" column="total_cases"/>
|
||||||
|
<result property="completedCases" column="completed_cases"/><result property="passedCases" column="passed_cases"/><result property="failedCases" column="failed_cases"/>
|
||||||
|
<result property="progress" column="progress"/>
|
||||||
|
<result property="startTime" column="start_time"/><result property="endTime" column="end_time"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<resultMap type="com.cmvr.aima.domain.vo.AimaTaskInstanceVo" id="AimaTaskInstanceVoResult">
|
||||||
|
<result property="id" column="id"/><result property="createBy" column="create_by"/><result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/><result property="updateTime" column="update_time"/><result property="remark" column="remark"/>
|
||||||
|
<result property="taskId" column="task_id"/><result property="taskCode" column="task_code"/><result property="taskName" column="task_name"/>
|
||||||
|
<result property="phoneId" column="phone_id"/><result property="phoneName" column="phone_name"/>
|
||||||
|
<result property="vehicleId" column="vehicle_id"/><result property="vehicleName" column="vehicle_name"/><result property="vin" column="vin"/>
|
||||||
|
<result property="executionNumber" column="execution_number"/><result property="status" column="status"/><result property="taskInsId" column="task_ins_id"/>
|
||||||
|
<result property="totalCases" column="total_cases"/>
|
||||||
|
<result property="completedCases" column="completed_cases"/><result property="passedCases" column="passed_cases"/><result property="failedCases" column="failed_cases"/>
|
||||||
|
<result property="progress" column="progress"/>
|
||||||
|
<result property="startTime" column="start_time"/><result property="endTime" column="end_time"/>
|
||||||
|
<result property="createByName" column="create_by_name"/><result property="updateByName" column="update_by_name"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectAimaTaskInstanceVo">
|
||||||
|
select id, create_by, create_time, update_by, update_time, remark, task_id, phone_id, vehicle_id, execution_number, status, task_ins_id, total_cases, completed_cases, passed_cases, failed_cases, progress, start_time, end_time from aima_task_instance
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectAimaTaskInstanceList" parameterType="AimaTaskInstance" resultMap="AimaTaskInstanceResult">
|
||||||
|
<include refid="selectAimaTaskInstanceVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="taskId != null and taskId != ''"> and task_id = #{taskId}</if>
|
||||||
|
<if test="phoneId != null and phoneId != ''"> and phone_id = #{phoneId}</if>
|
||||||
|
<if test="vehicleId != null and vehicleId != ''"> and vehicle_id = #{vehicleId}</if>
|
||||||
|
<if test="status != null"> and status = #{status}</if>
|
||||||
|
</where>
|
||||||
|
order by create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAimaTaskInstanceById" parameterType="String" resultMap="AimaTaskInstanceResult">
|
||||||
|
<include refid="selectAimaTaskInstanceVo"/> where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAimaTaskInstanceVoList" parameterType="com.cmvr.aima.domain.dto.AimaTaskInstanceQuery" resultMap="AimaTaskInstanceVoResult">
|
||||||
|
select ti.id, ti.create_by, ti.create_time, ti.update_by, ti.update_time, ti.remark,
|
||||||
|
ti.task_id, t.task_code, t.task_name,
|
||||||
|
ti.phone_id, p.phone_name, ti.vehicle_id, v.vehicle_name, v.vin,
|
||||||
|
ti.execution_number, ti.status, ti.task_ins_id,
|
||||||
|
ti.total_cases, ti.completed_cases, ti.passed_cases, ti.failed_cases, ti.progress,
|
||||||
|
ti.start_time, ti.end_time,
|
||||||
|
u1.nick_name as create_by_name, u2.nick_name as update_by_name
|
||||||
|
from aima_task_instance ti
|
||||||
|
left join aima_task t on ti.task_id = t.id
|
||||||
|
left join aima_phone p on ti.phone_id = p.id
|
||||||
|
left join aima_vehicle v on ti.vehicle_id = v.id
|
||||||
|
left join sys_user u1 on ti.create_by = u1.user_name
|
||||||
|
left join sys_user u2 on ti.update_by = u2.user_name
|
||||||
|
<where>
|
||||||
|
<if test="taskId != null and taskId != ''"> and ti.task_id = #{taskId}</if>
|
||||||
|
<if test="phoneId != null and phoneId != ''"> and ti.phone_id = #{phoneId}</if>
|
||||||
|
<if test="vehicleId != null and vehicleId != ''"> and ti.vehicle_id = #{vehicleId}</if>
|
||||||
|
<if test="status != null"> and ti.status = #{status}</if>
|
||||||
|
<if test="statusList != null and statusList.size() > 0">
|
||||||
|
and ti.status in
|
||||||
|
<foreach item="statusItem" collection="statusList" open="(" separator="," close=")">
|
||||||
|
#{statusItem}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
order by ti.create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertAimaTaskInstance" parameterType="AimaTaskInstance">
|
||||||
|
insert into aima_task_instance <trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">id,</if><if test="createBy != null">create_by,</if><if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if><if test="updateTime != null">update_time,</if><if test="remark != null">remark,</if>
|
||||||
|
<if test="taskId != null">task_id,</if><if test="phoneId != null">phone_id,</if>
|
||||||
|
<if test="vehicleId != null">vehicle_id,</if>
|
||||||
|
<if test="executionNumber != null">execution_number,</if><if test="status != null">status,</if><if test="totalCases != null">total_cases,</if>
|
||||||
|
<if test="completedCases != null">completed_cases,</if><if test="passedCases != null">passed_cases,</if><if test="failedCases != null">failed_cases,</if>
|
||||||
|
<if test="progress != null">progress,</if>
|
||||||
|
<if test="startTime != null">start_time,</if><if test="endTime != null">end_time,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">#{id},</if><if test="createBy != null">#{createBy},</if><if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if><if test="updateTime != null">#{updateTime},</if><if test="remark != null">#{remark},</if>
|
||||||
|
<if test="taskId != null">#{taskId},</if><if test="phoneId != null">#{phoneId},</if>
|
||||||
|
<if test="vehicleId != null">#{vehicleId},</if>
|
||||||
|
<if test="executionNumber != null">#{executionNumber},</if><if test="status != null">#{status},</if><if test="totalCases != null">#{totalCases},</if>
|
||||||
|
<if test="completedCases != null">#{completedCases},</if><if test="passedCases != null">#{passedCases},</if><if test="failedCases != null">#{failedCases},</if>
|
||||||
|
<if test="progress != null">#{progress},</if>
|
||||||
|
<if test="startTime != null">#{startTime},</if><if test="endTime != null">#{endTime},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateAimaTaskInstance" parameterType="AimaTaskInstance">
|
||||||
|
update aima_task_instance <trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="createBy != null">create_by = #{createBy},</if><if test="createTime != null">create_time = #{createTime},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if><if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if><if test="taskId != null">task_id = #{taskId},</if>
|
||||||
|
<if test="phoneId != null">phone_id = #{phoneId},</if>
|
||||||
|
<if test="vehicleId != null">vehicle_id = #{vehicleId},</if>
|
||||||
|
<if test="executionNumber != null">execution_number = #{executionNumber},</if>
|
||||||
|
<if test="status != null">status = #{status},</if><if test="totalCases != null">total_cases = #{totalCases},</if>
|
||||||
|
<if test="completedCases != null">completed_cases = #{completedCases},</if><if test="passedCases != null">passed_cases = #{passedCases},</if>
|
||||||
|
<if test="failedCases != null">failed_cases = #{failedCases},</if><if test="progress != null">progress = #{progress},</if>
|
||||||
|
<if test="startTime != null">start_time = #{startTime},</if><if test="endTime != null">end_time = #{endTime},</if>
|
||||||
|
<if test="taskInsId != null">task_ins_id = #{taskInsId},</if>
|
||||||
|
|
||||||
|
</trim> where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteAimaTaskInstanceById" parameterType="String">delete from aima_task_instance where id = #{id}</delete>
|
||||||
|
<delete id="deleteAimaTaskInstanceByIds" parameterType="String">
|
||||||
|
delete from aima_task_instance where id in <foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach>
|
||||||
|
</delete>
|
||||||
|
</mapper>
|
||||||
114
cmvr-iot-aima/src/main/resources/mapper/aima/AimaTaskMapper.xml
Normal file
114
cmvr-iot-aima/src/main/resources/mapper/aima/AimaTaskMapper.xml
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<?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.cmvr.aima.mapper.AimaTaskMapper">
|
||||||
|
<resultMap type="AimaTask" id="AimaTaskResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
<result property="taskCode" column="task_code"/>
|
||||||
|
<result property="taskName" column="task_name"/>
|
||||||
|
<result property="taskType" column="task_type"/>
|
||||||
|
<result property="phoneId" column="phone_id"/>
|
||||||
|
<result property="vehicleId" column="vehicle_id"/>
|
||||||
|
<result property="testCaseCount" column="test_case_count"/>
|
||||||
|
<result property="taskConfigId" column="task_config_id"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<resultMap type="com.cmvr.aima.domain.vo.AimaTaskVo" id="AimaTaskVoResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
<result property="taskCode" column="task_code"/>
|
||||||
|
<result property="taskName" column="task_name"/>
|
||||||
|
<result property="taskType" column="task_type"/>
|
||||||
|
<result property="phoneId" column="phone_id"/>
|
||||||
|
<result property="vehicleId" column="vehicle_id"/>
|
||||||
|
<result property="testCaseCount" column="test_case_count"/>
|
||||||
|
<result property="taskConfigId" column="task_config_id"/>
|
||||||
|
<result property="phoneName" column="phone_name"/>
|
||||||
|
<result property="vin" column="vin"/>
|
||||||
|
<result property="createByName" column="create_by_name"/>
|
||||||
|
<result property="updateByName" column="update_by_name"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectAimaTaskVo">
|
||||||
|
select id, create_by, create_time, update_by, update_time, remark, task_code, task_name, task_type, phone_id, vehicle_id, test_case_count, task_config_id from aima_task
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectAimaTaskList" parameterType="AimaTask" resultMap="AimaTaskResult">
|
||||||
|
<include refid="selectAimaTaskVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="taskCode != null and taskCode != ''"> and task_code = #{taskCode}</if>
|
||||||
|
<if test="taskName != null and taskName != ''"> and task_name like concat('%', #{taskName}, '%')</if>
|
||||||
|
<if test="taskType != null and taskType != ''"> and task_type = #{taskType}</if>
|
||||||
|
<if test="phoneId != null and phoneId != ''"> and phone_id = #{phoneId}</if>
|
||||||
|
<if test="vehicleId != null and vehicleId != ''"> and vehicle_id = #{vehicleId}</if>
|
||||||
|
</where>
|
||||||
|
order by create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAimaTaskById" parameterType="String" resultMap="AimaTaskResult">
|
||||||
|
<include refid="selectAimaTaskVo"/> where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAimaTaskVoList" parameterType="AimaTask" resultMap="AimaTaskVoResult">
|
||||||
|
select t.id, t.create_by, t.create_time, t.update_by, t.update_time, t.remark,
|
||||||
|
t.task_code, t.task_name, t.task_type, t.phone_id, t.vehicle_id,
|
||||||
|
t.test_case_count, t.task_config_id,
|
||||||
|
p.phone_name, v.vin,
|
||||||
|
u1.nick_name as create_by_name, u2.nick_name as update_by_name
|
||||||
|
from aima_task t
|
||||||
|
left join aima_phone p on t.phone_id = p.id
|
||||||
|
left join aima_vehicle v on t.vehicle_id = v.id
|
||||||
|
left join sys_user u1 on t.create_by = u1.user_name
|
||||||
|
left join sys_user u2 on t.update_by = u2.user_name
|
||||||
|
<where>
|
||||||
|
<if test="taskCode != null and taskCode != ''"> and t.task_code = #{taskCode}</if>
|
||||||
|
<if test="taskName != null and taskName != ''"> and t.task_name like concat('%', #{taskName}, '%')</if>
|
||||||
|
<if test="taskType != null and taskType != ''"> and t.task_type = #{taskType}</if>
|
||||||
|
<if test="phoneId != null and phoneId != ''"> and t.phone_id = #{phoneId}</if>
|
||||||
|
<if test="vehicleId != null and vehicleId != ''"> and t.vehicle_id = #{vehicleId}</if>
|
||||||
|
</where>
|
||||||
|
order by t.create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertAimaTask" parameterType="AimaTask">
|
||||||
|
insert into aima_task <trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">id,</if><if test="createBy != null">create_by,</if><if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if><if test="updateTime != null">update_time,</if><if test="remark != null">remark,</if>
|
||||||
|
<if test="taskCode != null">task_code,</if><if test="taskName != null">task_name,</if><if test="taskType != null">task_type,</if>
|
||||||
|
<if test="phoneId != null">phone_id,</if><if test="vehicleId != null">vehicle_id,</if>
|
||||||
|
<if test="testCaseCount != null">test_case_count,</if><if test="taskConfigId != null">task_config_id,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">#{id},</if><if test="createBy != null">#{createBy},</if><if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if><if test="updateTime != null">#{updateTime},</if><if test="remark != null">#{remark},</if>
|
||||||
|
<if test="taskCode != null">#{taskCode},</if><if test="taskName != null">#{taskName},</if><if test="taskType != null">#{taskType},</if>
|
||||||
|
<if test="phoneId != null">#{phoneId},</if><if test="vehicleId != null">#{vehicleId},</if>
|
||||||
|
<if test="testCaseCount != null">#{testCaseCount},</if><if test="taskConfigId != null">#{taskConfigId},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateAimaTask" parameterType="AimaTask">
|
||||||
|
update aima_task <trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="createBy != null">create_by = #{createBy},</if><if test="createTime != null">create_time = #{createTime},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if><if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if><if test="taskCode != null">task_code = #{taskCode},</if>
|
||||||
|
<if test="taskName != null">task_name = #{taskName},</if><if test="taskType != null">task_type = #{taskType},</if>
|
||||||
|
<if test="phoneId != null">phone_id = #{phoneId},</if>
|
||||||
|
<if test="vehicleId != null">vehicle_id = #{vehicleId},</if>
|
||||||
|
<if test="testCaseCount != null">test_case_count = #{testCaseCount},</if><if test="taskConfigId != null">task_config_id = #{taskConfigId},</if>
|
||||||
|
</trim> where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteAimaTaskById" parameterType="String">delete from aima_task where id = #{id}</delete>
|
||||||
|
<delete id="deleteAimaTaskByIds" parameterType="String">
|
||||||
|
delete from aima_task where id in <foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach>
|
||||||
|
</delete>
|
||||||
|
</mapper>
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
<?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.cmvr.aima.mapper.AimaTaskTestCaseMapper">
|
||||||
|
|
||||||
|
<insert id="batchInsertTaskTestCase">
|
||||||
|
INSERT INTO aima_task_test_case (task_id, test_case_id, sort_order) VALUES
|
||||||
|
<foreach collection="list" item="item" separator=",">
|
||||||
|
(#{item.taskId}, #{item.testCaseId}, #{item.sortOrder})
|
||||||
|
</foreach>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<delete id="deleteTaskTestCaseByTaskId" parameterType="String">
|
||||||
|
DELETE FROM aima_task_test_case WHERE task_id = #{taskId}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<select id="selectTestCaseIdsByTaskId" parameterType="String" resultType="String">
|
||||||
|
SELECT test_case_id FROM aima_task_test_case
|
||||||
|
WHERE task_id = #{taskId}
|
||||||
|
ORDER BY sort_order
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<delete id="deleteTaskTestCaseByTaskIds" parameterType="String">
|
||||||
|
DELETE FROM aima_task_test_case WHERE task_id IN
|
||||||
|
<foreach item="taskId" collection="array" open="(" separator="," close=")">
|
||||||
|
#{taskId}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@ -0,0 +1,167 @@
|
|||||||
|
<?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.cmvr.aima.mapper.AimaTestCaseMapper">
|
||||||
|
<resultMap type="AimaTestCase" id="AimaTestCaseResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
<result property="caseCode" column="case_code"/>
|
||||||
|
<result property="caseName" column="case_name"/>
|
||||||
|
<result property="caseCategory" column="case_category"/>
|
||||||
|
<result property="testDescription" column="test_description"/>
|
||||||
|
<result property="precondition" column="precondition"/>
|
||||||
|
<result property="testSteps" column="test_steps"/>
|
||||||
|
<result property="expectedResult" column="expected_result"/>
|
||||||
|
<result property="priority" column="priority"/>
|
||||||
|
<result property="enabled" column="enabled"/>
|
||||||
|
<result property="sortOrder" column="sort_order"/>
|
||||||
|
<result property="estimatedDuration" column="estimated_duration"/>
|
||||||
|
<result property="detectItemId" column="detect_item_id"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<resultMap type="com.cmvr.aima.domain.vo.AimaTestCaseVo" id="AimaTestCaseVoResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
<result property="caseCode" column="case_code"/>
|
||||||
|
<result property="caseName" column="case_name"/>
|
||||||
|
<result property="caseCategory" column="case_category"/>
|
||||||
|
<result property="testDescription" column="test_description"/>
|
||||||
|
<result property="precondition" column="precondition"/>
|
||||||
|
<result property="testSteps" column="test_steps"/>
|
||||||
|
<result property="expectedResult" column="expected_result"/>
|
||||||
|
<result property="priority" column="priority"/>
|
||||||
|
<result property="enabled" column="enabled"/>
|
||||||
|
<result property="sortOrder" column="sort_order"/>
|
||||||
|
<result property="estimatedDuration" column="estimated_duration"/>
|
||||||
|
<result property="detectItemId" column="detect_item_id"/>
|
||||||
|
<result property="configStatus" column="config_status"/>
|
||||||
|
<result property="createByName" column="create_by_name"/>
|
||||||
|
<result property="updateByName" column="update_by_name"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectAimaTestCaseVo">
|
||||||
|
select id, create_by, create_time, update_by, update_time, remark, case_code, case_name, case_category, test_description, precondition, test_steps, expected_result, priority, enabled, sort_order, estimated_duration, detect_item_id from aima_test_case
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectAimaTestCaseList" parameterType="AimaTestCase" resultMap="AimaTestCaseResult">
|
||||||
|
<include refid="selectAimaTestCaseVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="caseCode != null and caseCode != ''"> and case_code = #{caseCode}</if>
|
||||||
|
<if test="caseName != null and caseName != ''"> and case_name like concat('%', #{caseName}, '%')</if>
|
||||||
|
<if test="caseCategory != null and caseCategory != ''"> and case_category = #{caseCategory}</if>
|
||||||
|
<if test="enabled != null and enabled != ''"> and enabled = #{enabled}</if>
|
||||||
|
</where>
|
||||||
|
order by sort_order asc, create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAimaTestCaseById" parameterType="String" resultMap="AimaTestCaseResult">
|
||||||
|
<include refid="selectAimaTestCaseVo"/>
|
||||||
|
where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAimaTestCaseVoList" parameterType="AimaTestCase" resultMap="AimaTestCaseVoResult">
|
||||||
|
select tc.id, tc.create_by, tc.create_time, tc.update_by, tc.update_time, tc.remark,
|
||||||
|
tc.case_code, tc.case_name, tc.case_category, tc.test_description, tc.precondition,
|
||||||
|
tc.test_steps, tc.expected_result, tc.priority, tc.enabled, tc.sort_order,
|
||||||
|
tc.estimated_duration, tc.detect_item_id,
|
||||||
|
d.is_deploy as config_status,
|
||||||
|
u1.nick_name as create_by_name, u2.nick_name as update_by_name
|
||||||
|
from aima_test_case tc
|
||||||
|
left join te_detection_item d on tc.detect_item_id = d.id
|
||||||
|
left join sys_user u1 on tc.create_by = u1.user_name
|
||||||
|
left join sys_user u2 on tc.update_by = u2.user_name
|
||||||
|
<where>
|
||||||
|
<if test="caseCode != null and caseCode != ''"> and tc.case_code = #{caseCode}</if>
|
||||||
|
<if test="caseName != null and caseName != ''"> and tc.case_name like concat('%', #{caseName}, '%')</if>
|
||||||
|
<if test="caseCategory != null and caseCategory != ''"> and tc.case_category = #{caseCategory}</if>
|
||||||
|
<if test="enabled != null and enabled != ''"> and tc.enabled = #{enabled}</if>
|
||||||
|
</where>
|
||||||
|
order by tc.sort_order, tc.create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertAimaTestCase" parameterType="AimaTestCase">
|
||||||
|
insert into aima_test_case
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">id,</if>
|
||||||
|
<if test="createBy != null">create_by,</if>
|
||||||
|
<if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if>
|
||||||
|
<if test="updateTime != null">update_time,</if>
|
||||||
|
<if test="remark != null">remark,</if>
|
||||||
|
<if test="caseCode != null">case_code,</if>
|
||||||
|
<if test="caseName != null">case_name,</if>
|
||||||
|
<if test="caseCategory != null">case_category,</if>
|
||||||
|
<if test="testDescription != null">test_description,</if>
|
||||||
|
<if test="precondition != null">precondition,</if>
|
||||||
|
<if test="testSteps != null">test_steps,</if>
|
||||||
|
<if test="expectedResult != null">expected_result,</if>
|
||||||
|
<if test="priority != null">priority,</if>
|
||||||
|
<if test="enabled != null">enabled,</if>
|
||||||
|
<if test="sortOrder != null">sort_order,</if>
|
||||||
|
<if test="estimatedDuration != null">estimated_duration,</if>
|
||||||
|
<if test="detectItemId != null">detect_item_id,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">#{id},</if>
|
||||||
|
<if test="createBy != null">#{createBy},</if>
|
||||||
|
<if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if>
|
||||||
|
<if test="updateTime != null">#{updateTime},</if>
|
||||||
|
<if test="remark != null">#{remark},</if>
|
||||||
|
<if test="caseCode != null">#{caseCode},</if>
|
||||||
|
<if test="caseName != null">#{caseName},</if>
|
||||||
|
<if test="caseCategory != null">#{caseCategory},</if>
|
||||||
|
<if test="testDescription != null">#{testDescription},</if>
|
||||||
|
<if test="precondition != null">#{precondition},</if>
|
||||||
|
<if test="testSteps != null">#{testSteps},</if>
|
||||||
|
<if test="expectedResult != null">#{expectedResult},</if>
|
||||||
|
<if test="priority != null">#{priority},</if>
|
||||||
|
<if test="enabled != null">#{enabled},</if>
|
||||||
|
<if test="sortOrder != null">#{sortOrder},</if>
|
||||||
|
<if test="estimatedDuration != null">#{estimatedDuration},</if>
|
||||||
|
<if test="detectItemId != null">#{detectItemId},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateAimaTestCase" parameterType="AimaTestCase">
|
||||||
|
update aima_test_case
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="createBy != null">create_by = #{createBy},</if>
|
||||||
|
<if test="createTime != null">create_time = #{createTime},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||||
|
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
<if test="caseCode != null">case_code = #{caseCode},</if>
|
||||||
|
<if test="caseName != null">case_name = #{caseName},</if>
|
||||||
|
<if test="caseCategory != null">case_category = #{caseCategory},</if>
|
||||||
|
<if test="testDescription != null">test_description = #{testDescription},</if>
|
||||||
|
<if test="precondition != null">precondition = #{precondition},</if>
|
||||||
|
<if test="testSteps != null">test_steps = #{testSteps},</if>
|
||||||
|
<if test="expectedResult != null">expected_result = #{expectedResult},</if>
|
||||||
|
<if test="priority != null">priority = #{priority},</if>
|
||||||
|
<if test="enabled != null">enabled = #{enabled},</if>
|
||||||
|
<if test="sortOrder != null">sort_order = #{sortOrder},</if>
|
||||||
|
<if test="estimatedDuration != null">estimated_duration = #{estimatedDuration},</if>
|
||||||
|
<if test="detectItemId != null">detect_item_id = #{detectItemId},</if>
|
||||||
|
</trim>
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteAimaTestCaseById" parameterType="String">
|
||||||
|
delete from aima_test_case where id = #{id}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<delete id="deleteAimaTestCaseByIds" parameterType="String">
|
||||||
|
delete from aima_test_case where id in
|
||||||
|
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
</mapper>
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
<?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.cmvr.aima.mapper.AimaTestLogMapper">
|
||||||
|
<resultMap type="AimaTestLog" id="AimaTestLogResult">
|
||||||
|
<result property="id" column="id"/><result property="createBy" column="create_by"/><result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/><result property="updateTime" column="update_time"/><result property="remark" column="remark"/>
|
||||||
|
<result property="taskInstanceId" column="task_instance_id"/><result property="taskId" column="task_id"/><result property="taskName" column="task_name"/>
|
||||||
|
<result property="testCaseId" column="test_case_id"/><result property="caseName" column="case_name"/><result property="logLevel" column="log_level"/>
|
||||||
|
<result property="logType" column="log_type"/><result property="logContent" column="log_content"/><result property="logTime" column="log_time"/>
|
||||||
|
<result property="executionStep" column="execution_step"/><result property="actualResult" column="actual_result"/><result property="testStatus" column="test_status"/>
|
||||||
|
<result property="screenshotUrl" column="screenshot_url"/><result property="videoUrl" column="video_url"/><result property="errorStack" column="error_stack"/>
|
||||||
|
<result property="durationMs" column="duration_ms"/>
|
||||||
|
<result property="progress" column="progress"/>
|
||||||
|
<result property="status" column="status"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectAimaTestLogVo">
|
||||||
|
select id, create_by, create_time, update_by, update_time, remark, task_instance_id, task_id, task_name, test_case_id, case_name, log_level, log_type, log_content, log_time, execution_step, actual_result, test_status, screenshot_url, video_url, error_stack, duration_ms,progress,status from aima_test_log
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectAimaTestLogList" parameterType="AimaTestLog" resultMap="AimaTestLogResult">
|
||||||
|
<include refid="selectAimaTestLogVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="taskInstanceId != null and taskInstanceId != ''"> and task_instance_id = #{taskInstanceId}</if>
|
||||||
|
<if test="taskId != null and taskId != ''"> and task_id = #{taskId}</if>
|
||||||
|
<if test="testCaseId != null and testCaseId != ''"> and test_case_id = #{testCaseId}</if>
|
||||||
|
<if test="logLevel != null and logLevel != ''"> and log_level = #{logLevel}</if>
|
||||||
|
<if test="testStatus != null and testStatus != ''"> and test_status = #{testStatus}</if>
|
||||||
|
</where>
|
||||||
|
order by log_time
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAimaTestLogById" parameterType="String" resultMap="AimaTestLogResult">
|
||||||
|
<include refid="selectAimaTestLogVo"/> where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertAimaTestLog" parameterType="AimaTestLog">
|
||||||
|
insert into aima_test_log <trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">id,</if><if test="createBy != null">create_by,</if><if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if><if test="updateTime != null">update_time,</if><if test="remark != null">remark,</if>
|
||||||
|
<if test="taskInstanceId != null">task_instance_id,</if><if test="taskId != null">task_id,</if><if test="taskName != null">task_name,</if>
|
||||||
|
<if test="testCaseId != null">test_case_id,</if><if test="caseName != null">case_name,</if><if test="logLevel != null">log_level,</if>
|
||||||
|
<if test="logType != null">log_type,</if><if test="logContent != null">log_content,</if><if test="logTime != null">log_time,</if>
|
||||||
|
<if test="executionStep != null">execution_step,</if><if test="actualResult != null">actual_result,</if><if test="testStatus != null">test_status,</if>
|
||||||
|
<if test="screenshotUrl != null">screenshot_url,</if><if test="videoUrl != null">video_url,</if><if test="errorStack != null">error_stack,</if>
|
||||||
|
<if test="durationMs != null">duration_ms,</if>
|
||||||
|
<if test="progress != null">progress,</if>
|
||||||
|
<if test="status != null">status,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">#{id},</if><if test="createBy != null">#{createBy},</if><if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if><if test="updateTime != null">#{updateTime},</if><if test="remark != null">#{remark},</if>
|
||||||
|
<if test="taskInstanceId != null">#{taskInstanceId},</if><if test="taskId != null">#{taskId},</if><if test="taskName != null">#{taskName},</if>
|
||||||
|
<if test="testCaseId != null">#{testCaseId},</if><if test="caseName != null">#{caseName},</if><if test="logLevel != null">#{logLevel},</if>
|
||||||
|
<if test="logType != null">#{logType},</if><if test="logContent != null">#{logContent},</if><if test="logTime != null">#{logTime},</if>
|
||||||
|
<if test="executionStep != null">#{executionStep},</if><if test="actualResult != null">#{actualResult},</if><if test="testStatus != null">#{testStatus},</if>
|
||||||
|
<if test="screenshotUrl != null">#{screenshotUrl},</if><if test="videoUrl != null">#{videoUrl},</if><if test="errorStack != null">#{errorStack},</if>
|
||||||
|
<if test="durationMs != null">#{durationMs},</if>
|
||||||
|
<if test="progress != null">#{progress},</if>
|
||||||
|
<if test="status != null">#{status},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateAimaTestLog" parameterType="AimaTestLog">
|
||||||
|
update aima_test_log <trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="createBy != null">create_by = #{createBy},</if><if test="createTime != null">create_time = #{createTime},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if><if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if><if test="taskInstanceId != null">task_instance_id = #{taskInstanceId},</if>
|
||||||
|
<if test="taskId != null">task_id = #{taskId},</if><if test="taskName != null">task_name = #{taskName},</if>
|
||||||
|
<if test="testCaseId != null">test_case_id = #{testCaseId},</if><if test="caseName != null">case_name = #{caseName},</if>
|
||||||
|
<if test="logLevel != null">log_level = #{logLevel},</if><if test="logType != null">log_type = #{logType},</if>
|
||||||
|
<if test="logContent != null"> log_content = #{logContent},</if><if test="logTime != null">log_time = #{logTime},</if>
|
||||||
|
<if test="executionStep != null">execution_step = #{executionStep},</if><if test="actualResult != null">actual_result = #{actualResult},</if>
|
||||||
|
<if test="testStatus != null">test_status = #{testStatus},</if><if test="screenshotUrl != null">screenshot_url = #{screenshotUrl},</if>
|
||||||
|
<if test="videoUrl != null">video_url = #{videoUrl},</if><if test="errorStack != null">error_stack = #{errorStack},</if>
|
||||||
|
<if test="durationMs != null">duration_ms = #{durationMs},</if>
|
||||||
|
<if test="progress != null">progress = #{progress},</if>
|
||||||
|
<if test="status != null">status = #{status},</if>
|
||||||
|
</trim> where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteAimaTestLogById" parameterType="String">delete from aima_test_log where id = #{id}</delete>
|
||||||
|
<delete id="deleteAimaTestLogByIds" parameterType="String">
|
||||||
|
delete from aima_test_log where id in <foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach>
|
||||||
|
</delete>
|
||||||
|
</mapper>
|
||||||
@ -0,0 +1,102 @@
|
|||||||
|
<?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.cmvr.aima.mapper.AimaVehicleMapper">
|
||||||
|
|
||||||
|
<resultMap type="AimaVehicle" id="AimaVehicleResult">
|
||||||
|
<result property="id" column="id" />
|
||||||
|
<result property="createBy" column="create_by" />
|
||||||
|
<result property="createTime" column="create_time" />
|
||||||
|
<result property="updateBy" column="update_by" />
|
||||||
|
<result property="updateTime" column="update_time" />
|
||||||
|
<result property="remark" column="remark" />
|
||||||
|
<result property="vin" column="vin" />
|
||||||
|
<result property="vehicleModel" column="vehicle_model" />
|
||||||
|
<result property="vehicleName" column="vehicle_name" />
|
||||||
|
<result property="color" column="color" />
|
||||||
|
<result property="productionDate" column="production_date" />
|
||||||
|
<result property="status" column="status" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectAimaVehicleVo">
|
||||||
|
select id, create_by, create_time, update_by, update_time, remark, vin, vehicle_model, vehicle_name, color, production_date, status from aima_vehicle
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectAimaVehicleList" parameterType="AimaVehicle" resultMap="AimaVehicleResult">
|
||||||
|
<include refid="selectAimaVehicleVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="vin != null and vin != ''"> and vin = #{vin}</if>
|
||||||
|
<if test="vehicleModel != null and vehicleModel != ''"> and vehicle_model like concat('%', #{vehicleModel}, '%')</if>
|
||||||
|
<if test="vehicleName != null and vehicleName != ''"> and vehicle_name like concat('%', #{vehicleName}, '%')</if>
|
||||||
|
<if test="status != null and status != ''"> and status = #{status}</if>
|
||||||
|
</where>
|
||||||
|
order by create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAimaVehicleById" parameterType="String" resultMap="AimaVehicleResult">
|
||||||
|
<include refid="selectAimaVehicleVo"/>
|
||||||
|
where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertAimaVehicle" parameterType="AimaVehicle">
|
||||||
|
insert into aima_vehicle
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">id,</if>
|
||||||
|
<if test="createBy != null">create_by,</if>
|
||||||
|
<if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if>
|
||||||
|
<if test="updateTime != null">update_time,</if>
|
||||||
|
<if test="remark != null">remark,</if>
|
||||||
|
<if test="vin != null">vin,</if>
|
||||||
|
<if test="vehicleModel != null">vehicle_model,</if>
|
||||||
|
<if test="vehicleName != null">vehicle_name,</if>
|
||||||
|
<if test="color != null">color,</if>
|
||||||
|
<if test="productionDate != null">production_date,</if>
|
||||||
|
<if test="status != null">status,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">#{id},</if>
|
||||||
|
<if test="createBy != null">#{createBy},</if>
|
||||||
|
<if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if>
|
||||||
|
<if test="updateTime != null">#{updateTime},</if>
|
||||||
|
<if test="remark != null">#{remark},</if>
|
||||||
|
<if test="vin != null">#{vin},</if>
|
||||||
|
<if test="vehicleModel != null">#{vehicleModel},</if>
|
||||||
|
<if test="vehicleName != null">#{vehicleName},</if>
|
||||||
|
<if test="color != null">#{color},</if>
|
||||||
|
<if test="productionDate != null">#{productionDate},</if>
|
||||||
|
<if test="status != null">#{status},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateAimaVehicle" parameterType="AimaVehicle">
|
||||||
|
update aima_vehicle
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="createBy != null">create_by = #{createBy},</if>
|
||||||
|
<if test="createTime != null">create_time = #{createTime},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||||
|
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
<if test="vin != null">vin = #{vin},</if>
|
||||||
|
<if test="vehicleModel != null">vehicle_model = #{vehicleModel},</if>
|
||||||
|
<if test="vehicleName != null">vehicle_name = #{vehicleName},</if>
|
||||||
|
<if test="color != null">color = #{color},</if>
|
||||||
|
<if test="productionDate != null">production_date = #{productionDate},</if>
|
||||||
|
<if test="status != null">status = #{status},</if>
|
||||||
|
</trim>
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteAimaVehicleById" parameterType="String">
|
||||||
|
delete from aima_vehicle where id = #{id}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<delete id="deleteAimaVehicleByIds" parameterType="String">
|
||||||
|
delete from aima_vehicle where id in
|
||||||
|
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
</mapper>
|
||||||
@ -55,6 +55,12 @@
|
|||||||
<version>1.5.9</version>
|
<version>1.5.9</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>dev.onvoid.webrtc</groupId>
|
||||||
|
<artifactId>webrtc-java</artifactId>
|
||||||
|
<version>0.14.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@ -0,0 +1,887 @@
|
|||||||
|
package com.cmvr.edge.client.adapter;
|
||||||
|
|
||||||
|
import cmvr.api.Common;
|
||||||
|
import cmvr.api.MicPhoneServiceGrpc;
|
||||||
|
import cmvr.api.MicrophoneCommand;
|
||||||
|
import cmvr.api.SpeakerCommand;
|
||||||
|
import cmvr.api.SpeakerServiceGrpc;
|
||||||
|
import com.cmvr.edge.client.manage.GrpcServiceManager;
|
||||||
|
import com.cmvr.edge.client.utils.EdgeCommonUtil;
|
||||||
|
import com.google.protobuf.ByteString;
|
||||||
|
import io.grpc.Status;
|
||||||
|
import io.grpc.stub.ClientCallStreamObserver;
|
||||||
|
import io.grpc.stub.ClientResponseObserver;
|
||||||
|
import io.grpc.stub.StreamObserver;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实时语音对讲 gRPC 适配层。
|
||||||
|
*
|
||||||
|
* <p>当前机器人侧不再使用旧的 RobotAudio 双向流 proto,而是拆成两个现有服务:
|
||||||
|
* 浏览器 -> 机器人:SpeakerService.StreamAudio 客户端流;
|
||||||
|
* 机器人 -> 浏览器:MicPhoneService.StreamAudio 服务端流。</p>
|
||||||
|
*
|
||||||
|
* <p>音频格式固定为 PCM_S16LE / 48000Hz / 单声道 / 10ms / 960 bytes。
|
||||||
|
* 所有发送到 gRPC StreamObserver 的动作都绑定到会话内单线程,避免并发 onNext 引发底层崩溃。</p>
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RobotAudioGrpcAdapter {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(RobotAudioGrpcAdapter.class);
|
||||||
|
|
||||||
|
private static final int SAMPLE_RATE = 48000;
|
||||||
|
private static final int CHANNELS = 1;
|
||||||
|
private static final int BITS_PER_SAMPLE = 16;
|
||||||
|
private static final int FRAME_MS = 10;
|
||||||
|
private static final int FRAME_SAMPLES = SAMPLE_RATE * FRAME_MS / 1000;
|
||||||
|
private static final int FRAME_BYTES = FRAME_SAMPLES * CHANNELS * (BITS_PER_SAMPLE / 8);
|
||||||
|
private static final String CODEC = "PCM_S16LE";
|
||||||
|
|
||||||
|
private static final int MAX_QUEUED_BROWSER_FRAMES = 10;
|
||||||
|
private static final int TARGET_QUEUED_BROWSER_FRAMES = 2;
|
||||||
|
private static final long HEARTBEAT_INTERVAL_MS = 1000L;
|
||||||
|
private static final long HEARTBEAT_DEADLINE_MS = 2000L;
|
||||||
|
|
||||||
|
private final GrpcServiceManager grpcServiceManager;
|
||||||
|
private final ConcurrentMap<String, RobotAudioStream> streams = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public RobotAudioStream openStream(String terminalId,
|
||||||
|
String deviceId,
|
||||||
|
String sessionId,
|
||||||
|
String operatorId,
|
||||||
|
RobotAudioStreamListener listener) {
|
||||||
|
return openStream(terminalId, deviceId, deviceId, sessionId, operatorId, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RobotAudioStream openStream(String terminalId,
|
||||||
|
String speakerDeviceId,
|
||||||
|
String micDeviceId,
|
||||||
|
String sessionId,
|
||||||
|
String operatorId,
|
||||||
|
RobotAudioStreamListener listener) {
|
||||||
|
SpeakerServiceGrpc.SpeakerServiceStub speakerStub =
|
||||||
|
grpcServiceManager.getGrpcClient(terminalId, SpeakerServiceGrpc.SpeakerServiceStub.class);
|
||||||
|
MicPhoneServiceGrpc.MicPhoneServiceStub micStub =
|
||||||
|
grpcServiceManager.getGrpcClient(terminalId, MicPhoneServiceGrpc.MicPhoneServiceStub.class);
|
||||||
|
SpeakerServiceGrpc.SpeakerServiceBlockingStub speakerBlockingStub =
|
||||||
|
grpcServiceManager.getGrpcClient(terminalId, SpeakerServiceGrpc.SpeakerServiceBlockingStub.class);
|
||||||
|
MicPhoneServiceGrpc.MicPhoneServiceBlockingStub micBlockingStub =
|
||||||
|
grpcServiceManager.getGrpcClient(terminalId, MicPhoneServiceGrpc.MicPhoneServiceBlockingStub.class);
|
||||||
|
|
||||||
|
preflightDeviceStatus(speakerBlockingStub, micBlockingStub, speakerDeviceId, micDeviceId, sessionId);
|
||||||
|
|
||||||
|
RobotAudioStream stream = new RobotAudioStream(
|
||||||
|
terminalId, speakerDeviceId, micDeviceId, sessionId, operatorId, speakerStub, micStub, listener);
|
||||||
|
RobotAudioStream exists = streams.putIfAbsent(sessionId, stream);
|
||||||
|
if (exists != null) {
|
||||||
|
throw new IllegalStateException("实时语音会话已存在:" + sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
stream.start();
|
||||||
|
log.info("实时对讲 gRPC 流已创建,sessionId={},terminalId={},speakerDeviceId={},micDeviceId={},operatorId={},sampleRate={},channels={},bits={},frameMs={},frameBytes={}",
|
||||||
|
sessionId, terminalId, speakerDeviceId, micDeviceId, operatorId, SAMPLE_RATE, CHANNELS, BITS_PER_SAMPLE, FRAME_MS, FRAME_BYTES);
|
||||||
|
return stream;
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
streams.remove(sessionId, stream);
|
||||||
|
stream.closeLocalResources();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void destroy() {
|
||||||
|
for (RobotAudioStream stream : streams.values()) {
|
||||||
|
try {
|
||||||
|
stream.cancel("application shutdown");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("关闭实时语音流异常,sessionId={}", stream.getSessionId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
streams.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void preflightDeviceStatus(SpeakerServiceGrpc.SpeakerServiceBlockingStub speakerStub,
|
||||||
|
MicPhoneServiceGrpc.MicPhoneServiceBlockingStub micStub,
|
||||||
|
String speakerDeviceId,
|
||||||
|
String micDeviceId,
|
||||||
|
String sessionId) {
|
||||||
|
try {
|
||||||
|
SpeakerCommand.GetSpeakerStateCommand.Request speakerRequest = SpeakerCommand.GetSpeakerStateCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(speakerDeviceId))
|
||||||
|
.build();
|
||||||
|
SpeakerCommand.GetSpeakerStateCommand.Feedback speakerFeedback =
|
||||||
|
speakerStub.withDeadlineAfter(HEARTBEAT_DEADLINE_MS, TimeUnit.MILLISECONDS).getStatus(speakerRequest);
|
||||||
|
if (speakerFeedback != null && speakerFeedback.hasHeader() && !speakerFeedback.getHeader().getSuccess()) {
|
||||||
|
throw new IllegalStateException("speaker device unavailable: " + speakerFeedback.getHeader().getErrorMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
MicrophoneCommand.GetMicStateCommand.Request micRequest = MicrophoneCommand.GetMicStateCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(micDeviceId))
|
||||||
|
.build();
|
||||||
|
MicrophoneCommand.GetMicStateCommand.Feedback micFeedback =
|
||||||
|
micStub.withDeadlineAfter(HEARTBEAT_DEADLINE_MS, TimeUnit.MILLISECONDS).getStatus(micRequest);
|
||||||
|
if (micFeedback != null && micFeedback.hasHeader() && !micFeedback.getHeader().getSuccess()) {
|
||||||
|
throw new IllegalStateException("microphone device unavailable: " + micFeedback.getHeader().getErrorMessage());
|
||||||
|
}
|
||||||
|
log.info("实时对讲设备预检通过,sessionId={},speakerDeviceId={},micDeviceId={}", sessionId, speakerDeviceId, micDeviceId);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
log.error("实时对讲设备预检失败,sessionId={},speakerDeviceId={},micDeviceId={}", sessionId, speakerDeviceId, micDeviceId, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface RobotAudioStreamListener {
|
||||||
|
void onStarted(String sessionId, boolean accepted, String message);
|
||||||
|
|
||||||
|
void onRobotAudio(String sessionId, long sequence, long timestampMs, byte[] pcm);
|
||||||
|
|
||||||
|
void onHeartbeat(String sessionId, long timestampMs);
|
||||||
|
|
||||||
|
void onRobotStop(String sessionId, String reason);
|
||||||
|
|
||||||
|
void onError(String sessionId, Throwable throwable);
|
||||||
|
|
||||||
|
void onCompleted(String sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RobotAudioStream {
|
||||||
|
private final String terminalId;
|
||||||
|
private final String speakerDeviceId;
|
||||||
|
private final String micDeviceId;
|
||||||
|
private final String sessionId;
|
||||||
|
private final String operatorId;
|
||||||
|
private final SpeakerServiceGrpc.SpeakerServiceStub speakerStub;
|
||||||
|
private final MicPhoneServiceGrpc.MicPhoneServiceStub micStub;
|
||||||
|
private final RobotAudioStreamListener listener;
|
||||||
|
private final ScheduledExecutorService sendExecutor;
|
||||||
|
private final ArrayBlockingQueue<byte[]> browserFrameQueue = new ArrayBlockingQueue<>(MAX_QUEUED_BROWSER_FRAMES);
|
||||||
|
private final Object browserBufferLock = new Object();
|
||||||
|
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||||
|
private final AtomicBoolean terminalNotified = new AtomicBoolean(false);
|
||||||
|
private final AtomicBoolean heartbeatInFlight = new AtomicBoolean(false);
|
||||||
|
private final AtomicLong outboundSequence = new AtomicLong(0);
|
||||||
|
private final AtomicLong inboundSequence = new AtomicLong(0);
|
||||||
|
private final AtomicLong enqueued = new AtomicLong(0);
|
||||||
|
private final AtomicLong sent = new AtomicLong(0);
|
||||||
|
private final AtomicLong dropped = new AtomicLong(0);
|
||||||
|
|
||||||
|
private volatile StreamObserver<SpeakerCommand.StreamSpeakerAudioCommand.Request> speakerRequestObserver;
|
||||||
|
private volatile ClientCallStreamObserver<MicrophoneCommand.StreamMicAudioCommand.Request> micRequestObserver;
|
||||||
|
private volatile ScheduledFuture<?> sendFuture;
|
||||||
|
private volatile ScheduledFuture<?> heartbeatFuture;
|
||||||
|
private volatile long lastStatsLogAt;
|
||||||
|
private volatile byte[] pendingBrowserBytes = new byte[0];
|
||||||
|
|
||||||
|
private RobotAudioStream(String terminalId,
|
||||||
|
String speakerDeviceId,
|
||||||
|
String micDeviceId,
|
||||||
|
String sessionId,
|
||||||
|
String operatorId,
|
||||||
|
SpeakerServiceGrpc.SpeakerServiceStub speakerStub,
|
||||||
|
MicPhoneServiceGrpc.MicPhoneServiceStub micStub,
|
||||||
|
RobotAudioStreamListener listener) {
|
||||||
|
this.terminalId = terminalId;
|
||||||
|
this.speakerDeviceId = speakerDeviceId;
|
||||||
|
this.micDeviceId = micDeviceId;
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
this.operatorId = operatorId;
|
||||||
|
this.speakerStub = speakerStub;
|
||||||
|
this.micStub = micStub;
|
||||||
|
this.listener = listener;
|
||||||
|
this.sendExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("robot-audio-send-" + sessionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void start() {
|
||||||
|
openSpeakerStream();
|
||||||
|
openMicStream();
|
||||||
|
this.sendFuture = sendExecutor.scheduleAtFixedRate(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
sendOneBrowserFrame();
|
||||||
|
}
|
||||||
|
}, 0L, FRAME_MS, TimeUnit.MILLISECONDS);
|
||||||
|
this.heartbeatFuture = sendExecutor.scheduleAtFixedRate(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
probeHeartbeat();
|
||||||
|
}
|
||||||
|
}, HEARTBEAT_INTERVAL_MS, HEARTBEAT_INTERVAL_MS, TimeUnit.MILLISECONDS);
|
||||||
|
listener.onStarted(sessionId, true, "audio stream started");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openSpeakerStream() {
|
||||||
|
StreamObserver<SpeakerCommand.StreamSpeakerAudioCommand.Feedback> responseObserver =
|
||||||
|
new StreamObserver<SpeakerCommand.StreamSpeakerAudioCommand.Feedback>() {
|
||||||
|
@Override
|
||||||
|
public void onNext(SpeakerCommand.StreamSpeakerAudioCommand.Feedback feedback) {
|
||||||
|
if (closed.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (feedback != null && feedback.hasHeader() && !feedback.getHeader().getSuccess()) {
|
||||||
|
fail("speaker feedback", new IllegalStateException("speaker stream feedback failed: " + feedback.getHeader().getErrorMessage()));
|
||||||
|
} else {
|
||||||
|
listener.onHeartbeat(sessionId, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable t) {
|
||||||
|
if (closed.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fail("speaker stream", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCompleted() {
|
||||||
|
if (closed.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
completeFromRemote();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.speakerRequestObserver = speakerStub.streamAudio(responseObserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openMicStream() {
|
||||||
|
MicrophoneCommand.StreamMicAudioCommand.Request request = MicrophoneCommand.StreamMicAudioCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(micDeviceId))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
micStub.streamAudio(request,
|
||||||
|
new ClientResponseObserver<MicrophoneCommand.StreamMicAudioCommand.Request, MicrophoneCommand.StreamMicAudioCommand.Feedback>() {
|
||||||
|
@Override
|
||||||
|
public void beforeStart(ClientCallStreamObserver<MicrophoneCommand.StreamMicAudioCommand.Request> requestStream) {
|
||||||
|
micRequestObserver = requestStream;
|
||||||
|
requestStream.disableAutoInboundFlowControl();
|
||||||
|
log.info("麦克风音频流已启用手动入站流控,sessionId={},micDeviceId={}", sessionId, micDeviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(MicrophoneCommand.StreamMicAudioCommand.Feedback feedback) {
|
||||||
|
handleMicFeedback(feedback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable t) {
|
||||||
|
if (closed.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fail("mic stream", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCompleted() {
|
||||||
|
if (closed.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
completeFromRemote();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
requestNextMicFrame(1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收浏览器 WebSocket 二进制 PCM。允许前端一次发多帧或半帧,这里按 10ms 固定帧重组。
|
||||||
|
*/
|
||||||
|
public void sendAudio(byte[] pcm) {
|
||||||
|
if (closed.get() || pcm == null || pcm.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
synchronized (browserBufferLock) {
|
||||||
|
byte[] merged = new byte[pendingBrowserBytes.length + pcm.length];
|
||||||
|
System.arraycopy(pendingBrowserBytes, 0, merged, 0, pendingBrowserBytes.length);
|
||||||
|
System.arraycopy(pcm, 0, merged, pendingBrowserBytes.length, pcm.length);
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
while (merged.length - offset >= FRAME_BYTES) {
|
||||||
|
byte[] frame = Arrays.copyOfRange(merged, offset, offset + FRAME_BYTES);
|
||||||
|
enqueueBrowserFrame(frame);
|
||||||
|
offset += FRAME_BYTES;
|
||||||
|
}
|
||||||
|
pendingBrowserBytes = Arrays.copyOfRange(merged, offset, merged.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendHeartbeat() {
|
||||||
|
if (!closed.get()) {
|
||||||
|
probeHeartbeat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendStop(String reason) {
|
||||||
|
if (!closed.compareAndSet(false, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("关闭实时对讲 gRPC 流,sessionId={},reason={}", sessionId, reason);
|
||||||
|
sendExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
completeSpeakerStream();
|
||||||
|
cancelMicStream("browser stop");
|
||||||
|
stopTerminalAudio();
|
||||||
|
closeLocalResources();
|
||||||
|
streams.remove(sessionId, RobotAudioStream.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel(String reason) {
|
||||||
|
if (!closed.compareAndSet(false, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.warn("取消实时对讲 gRPC 流,sessionId={},reason={}", sessionId, reason);
|
||||||
|
sendExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
errorSpeakerStream(reason);
|
||||||
|
cancelMicStream(reason);
|
||||||
|
stopTerminalAudio();
|
||||||
|
closeLocalResources();
|
||||||
|
streams.remove(sessionId, RobotAudioStream.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSessionId() {
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTerminalId() {
|
||||||
|
return terminalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceId() {
|
||||||
|
return speakerDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enqueueBrowserFrame(byte[] frame) {
|
||||||
|
if (browserFrameQueue.remainingCapacity() == 0) {
|
||||||
|
int targetDrops = Math.max(1, browserFrameQueue.size() - TARGET_QUEUED_BROWSER_FRAMES + 1);
|
||||||
|
for (int i = 0; i < targetDrops; i++) {
|
||||||
|
if (browserFrameQueue.poll() != null) {
|
||||||
|
dropped.incrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (browserFrameQueue.offer(frame)) {
|
||||||
|
enqueued.incrementAndGet();
|
||||||
|
} else {
|
||||||
|
dropped.incrementAndGet();
|
||||||
|
}
|
||||||
|
logBrowserAudioStatsIfNeeded("browserAudioEnqueue");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendOneBrowserFrame() {
|
||||||
|
if (closed.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] frame = browserFrameQueue.poll();
|
||||||
|
if (frame == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StreamObserver<SpeakerCommand.StreamSpeakerAudioCommand.Request> observer = speakerRequestObserver;
|
||||||
|
if (observer == null) {
|
||||||
|
dropped.incrementAndGet();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long sequence = outboundSequence.incrementAndGet();
|
||||||
|
long timestampMs = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
observer.onNext(buildSpeakerAudioRequest(frame, timestampMs));
|
||||||
|
sent.incrementAndGet();
|
||||||
|
logGrpcOutboundFormatIfNeeded(sequence, timestampMs, frame);
|
||||||
|
logPcmStatsIfNeeded("grpc-outbound-browser", sequence, timestampMs, frame);
|
||||||
|
logBrowserAudioStatsIfNeeded("browserAudioGrpcSend");
|
||||||
|
} catch (Throwable t) {
|
||||||
|
fail("speaker send", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpeakerCommand.StreamSpeakerAudioCommand.Request buildSpeakerAudioRequest(byte[] frame, long timestampMs) {
|
||||||
|
Common.AudioData audio = Common.AudioData.newBuilder()
|
||||||
|
.setData(ByteString.copyFrom(frame))
|
||||||
|
.setSampleRate(SAMPLE_RATE)
|
||||||
|
.setChannels(CHANNELS)
|
||||||
|
.setFormat(Common.AudioData.AudioFormat.PCM)
|
||||||
|
.setCodec(CODEC)
|
||||||
|
.setPts(timestampMs)
|
||||||
|
.setNbSamples(FRAME_SAMPLES)
|
||||||
|
.build();
|
||||||
|
return SpeakerCommand.StreamSpeakerAudioCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(speakerDeviceId))
|
||||||
|
.setAudio(audio)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMicFeedback(MicrophoneCommand.StreamMicAudioCommand.Feedback feedback) {
|
||||||
|
if (closed.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (feedback == null) {
|
||||||
|
listener.onHeartbeat(sessionId, System.currentTimeMillis());
|
||||||
|
requestNextMicFrame(FRAME_MS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (feedback.hasHeader() && !feedback.getHeader().getSuccess()) {
|
||||||
|
fail("mic feedback", new IllegalStateException("microphone stream feedback failed: " + feedback.getHeader().getErrorMessage()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
listener.onHeartbeat(sessionId, System.currentTimeMillis());
|
||||||
|
if (!feedback.hasAudio()) {
|
||||||
|
requestNextMicFrame(FRAME_MS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common.AudioData audio = feedback.getAudio();
|
||||||
|
byte[] pcm = audio.getData().toByteArray();
|
||||||
|
if (!validateInboundAudio(audio, pcm)) {
|
||||||
|
requestNextMicFrame(FRAME_MS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long audioDurationMs = calculateAudioDurationMs(audio, pcm);
|
||||||
|
long sequence = inboundSequence.incrementAndGet();
|
||||||
|
long timestampMs = audio.getPts() > 0 ? audio.getPts() : System.currentTimeMillis();
|
||||||
|
logGrpcInboundFormatIfNeeded(sequence, timestampMs, audio, pcm);
|
||||||
|
logPcmStatsIfNeeded("grpc-inbound-robot", sequence, timestampMs, pcm);
|
||||||
|
byte[] normalizedPcm = normalizeInboundAudio(audio, pcm, sequence, timestampMs);
|
||||||
|
logPcmStatsIfNeeded("webrtc-outbound-robot-normalized", sequence, timestampMs, normalizedPcm);
|
||||||
|
try {
|
||||||
|
listener.onRobotAudio(sessionId, sequence, timestampMs, normalizedPcm);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.error("投递机器人音频到业务层失败,sessionId={},sequence={}", sessionId, sequence, t);
|
||||||
|
fail("business callback", t);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
requestNextMicFrame(audioDurationMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateInboundAudio(Common.AudioData audio, byte[] pcm) {
|
||||||
|
if (pcm == null || pcm.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((pcm.length & 1) != 0) {
|
||||||
|
log.warn("机器人上行 PCM 字节数不是偶数,sessionId={},bytes={}", sessionId, pcm.length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (audio.getFormat() != Common.AudioData.AudioFormat.PCM) {
|
||||||
|
log.warn("机器人上行音频格式不是 PCM,sessionId={},format={}", sessionId, audio.getFormat());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String codec = audio.getCodec();
|
||||||
|
if (codec != null && codec.length() > 0 && !CODEC.equalsIgnoreCase(codec)) {
|
||||||
|
log.warn("机器人上行编码不匹配,sessionId={},codec={},expected={}", sessionId, codec, CODEC);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long calculateAudioDurationMs(Common.AudioData audio, byte[] pcm) {
|
||||||
|
int sampleRate = audio.getSampleRate() <= 0 ? SAMPLE_RATE : audio.getSampleRate();
|
||||||
|
int channels = audio.getChannels() <= 0 ? CHANNELS : audio.getChannels();
|
||||||
|
int samples = audio.getNbSamples();
|
||||||
|
if (samples <= 0 && pcm != null && pcm.length > 0) {
|
||||||
|
samples = pcm.length / 2 / Math.max(1, channels);
|
||||||
|
}
|
||||||
|
if (sampleRate <= 0 || samples <= 0) {
|
||||||
|
return FRAME_MS;
|
||||||
|
}
|
||||||
|
return Math.max(1L, Math.round(samples * 1000.0D / sampleRate));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestNextMicFrame(long delayMs) {
|
||||||
|
if (closed.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final long safeDelayMs = Math.max(1L, delayMs);
|
||||||
|
sendExecutor.schedule(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (closed.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ClientCallStreamObserver<MicrophoneCommand.StreamMicAudioCommand.Request> observer = micRequestObserver;
|
||||||
|
if (observer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
observer.request(1);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
fail("mic flow-control request", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, safeDelayMs, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] normalizeInboundAudio(Common.AudioData audio, byte[] pcm, long sequence, long timestampMs) {
|
||||||
|
int sourceSampleRate = audio.getSampleRate() <= 0 ? SAMPLE_RATE : audio.getSampleRate();
|
||||||
|
int sourceChannels = audio.getChannels() <= 0 ? CHANNELS : audio.getChannels();
|
||||||
|
if (sourceSampleRate == SAMPLE_RATE && sourceChannels == CHANNELS) {
|
||||||
|
return pcm;
|
||||||
|
}
|
||||||
|
|
||||||
|
short[] monoSamples = decodeToMonoSamples(pcm, sourceChannels);
|
||||||
|
short[] normalizedSamples = sourceSampleRate == SAMPLE_RATE
|
||||||
|
? monoSamples
|
||||||
|
: resampleLinear(monoSamples, sourceSampleRate, SAMPLE_RATE);
|
||||||
|
byte[] normalizedPcm = encodeMonoSamples(normalizedSamples);
|
||||||
|
if (sequence == 1 || sequence % 500 == 0) {
|
||||||
|
log.info("机器人上行音频已标准化,sessionId={},sourceSampleRate={},sourceChannels={},targetSampleRate={},targetChannels={},sourceBytes={},targetBytes={},sequence={},timestampMs={}",
|
||||||
|
sessionId, sourceSampleRate, sourceChannels, SAMPLE_RATE, CHANNELS, pcm.length, normalizedPcm.length, sequence, timestampMs);
|
||||||
|
}
|
||||||
|
return normalizedPcm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private short[] decodeToMonoSamples(byte[] pcm, int sourceChannels) {
|
||||||
|
int channels = Math.max(1, sourceChannels);
|
||||||
|
int frameCount = pcm.length / 2 / channels;
|
||||||
|
short[] mono = new short[frameCount];
|
||||||
|
for (int frame = 0; frame < frameCount; frame++) {
|
||||||
|
int sum = 0;
|
||||||
|
for (int channel = 0; channel < channels; channel++) {
|
||||||
|
int sampleIndex = (frame * channels + channel) * 2;
|
||||||
|
int lo = pcm[sampleIndex] & 0xff;
|
||||||
|
int hi = pcm[sampleIndex + 1];
|
||||||
|
sum += (short) ((hi << 8) | lo);
|
||||||
|
}
|
||||||
|
mono[frame] = (short) (sum / channels);
|
||||||
|
}
|
||||||
|
return mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
private short[] resampleLinear(short[] input, int sourceSampleRate, int targetSampleRate) {
|
||||||
|
if (input.length == 0 || sourceSampleRate <= 0 || targetSampleRate <= 0) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
int outputLength = Math.max(1, (int) Math.round(input.length * (targetSampleRate / (double) sourceSampleRate)));
|
||||||
|
short[] output = new short[outputLength];
|
||||||
|
double sourceStep = sourceSampleRate / (double) targetSampleRate;
|
||||||
|
for (int i = 0; i < outputLength; i++) {
|
||||||
|
double sourceIndex = i * sourceStep;
|
||||||
|
int left = (int) sourceIndex;
|
||||||
|
int right = Math.min(left + 1, input.length - 1);
|
||||||
|
double fraction = sourceIndex - left;
|
||||||
|
double value = input[left] + (input[right] - input[left]) * fraction;
|
||||||
|
output[i] = clampToShort((int) Math.round(value));
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] encodeMonoSamples(short[] samples) {
|
||||||
|
byte[] pcm = new byte[samples.length * 2];
|
||||||
|
for (int i = 0; i < samples.length; i++) {
|
||||||
|
pcm[i * 2] = (byte) (samples[i] & 0xff);
|
||||||
|
pcm[i * 2 + 1] = (byte) ((samples[i] >> 8) & 0xff);
|
||||||
|
}
|
||||||
|
return pcm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private short clampToShort(int value) {
|
||||||
|
if (value > Short.MAX_VALUE) {
|
||||||
|
return Short.MAX_VALUE;
|
||||||
|
}
|
||||||
|
if (value < Short.MIN_VALUE) {
|
||||||
|
return Short.MIN_VALUE;
|
||||||
|
}
|
||||||
|
return (short) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void probeHeartbeat() {
|
||||||
|
if (closed.get() || !heartbeatInFlight.compareAndSet(false, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MicrophoneCommand.GetMicStateCommand.Request request = MicrophoneCommand.GetMicStateCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(micDeviceId))
|
||||||
|
.build();
|
||||||
|
micStub.withDeadlineAfter(HEARTBEAT_DEADLINE_MS, TimeUnit.MILLISECONDS).getStatus(request,
|
||||||
|
new StreamObserver<MicrophoneCommand.GetMicStateCommand.Feedback>() {
|
||||||
|
@Override
|
||||||
|
public void onNext(MicrophoneCommand.GetMicStateCommand.Feedback feedback) {
|
||||||
|
if (feedback != null && feedback.hasHeader() && !feedback.getHeader().getSuccess()) {
|
||||||
|
log.warn("实时对讲麦克风心跳返回失败,sessionId={},message={}", sessionId, feedback.getHeader().getErrorMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
listener.onHeartbeat(sessionId, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable t) {
|
||||||
|
log.debug("实时对讲麦克风心跳探测失败,sessionId={}", sessionId, t);
|
||||||
|
heartbeatInFlight.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCompleted() {
|
||||||
|
heartbeatInFlight.set(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fail(String source, Throwable throwable) {
|
||||||
|
if (!closed.compareAndSet(false, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Throwable actual = throwable == null ? new RuntimeException("audio stream failed") : throwable;
|
||||||
|
log.error("实时对讲 gRPC 流异常,source={},sessionId={},terminalId={},speakerDeviceId={},micDeviceId={}",
|
||||||
|
source, sessionId, terminalId, speakerDeviceId, micDeviceId, actual);
|
||||||
|
sendExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
errorSpeakerStream(actual.getMessage());
|
||||||
|
cancelMicStream(actual.getMessage());
|
||||||
|
stopTerminalAudio();
|
||||||
|
closeLocalResources();
|
||||||
|
streams.remove(sessionId, RobotAudioStream.this);
|
||||||
|
if (terminalNotified.compareAndSet(false, true)) {
|
||||||
|
listener.onError(sessionId, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void completeFromRemote() {
|
||||||
|
if (!closed.compareAndSet(false, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("实时对讲 gRPC 流远端结束,sessionId={},terminalId={},speakerDeviceId={},micDeviceId={}", sessionId, terminalId, speakerDeviceId, micDeviceId);
|
||||||
|
sendExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
completeSpeakerStream();
|
||||||
|
cancelMicStream("remote completed");
|
||||||
|
closeLocalResources();
|
||||||
|
streams.remove(sessionId, RobotAudioStream.this);
|
||||||
|
if (terminalNotified.compareAndSet(false, true)) {
|
||||||
|
listener.onCompleted(sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void completeSpeakerStream() {
|
||||||
|
StreamObserver<SpeakerCommand.StreamSpeakerAudioCommand.Request> observer = speakerRequestObserver;
|
||||||
|
speakerRequestObserver = null;
|
||||||
|
if (observer != null) {
|
||||||
|
try {
|
||||||
|
observer.onCompleted();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.debug("完成扬声器音频流异常,sessionId={}", sessionId, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void errorSpeakerStream(String reason) {
|
||||||
|
StreamObserver<SpeakerCommand.StreamSpeakerAudioCommand.Request> observer = speakerRequestObserver;
|
||||||
|
speakerRequestObserver = null;
|
||||||
|
if (observer != null) {
|
||||||
|
try {
|
||||||
|
observer.onError(Status.CANCELLED.withDescription(reason == null ? "audio cancelled" : reason).asRuntimeException());
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.debug("取消扬声器音频流异常,sessionId={}", sessionId, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelMicStream(String reason) {
|
||||||
|
ClientCallStreamObserver<MicrophoneCommand.StreamMicAudioCommand.Request> observer = micRequestObserver;
|
||||||
|
micRequestObserver = null;
|
||||||
|
if (observer != null) {
|
||||||
|
try {
|
||||||
|
observer.cancel(reason == null ? "audio cancelled" : reason, null);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.debug("取消麦克风音频流异常,sessionId={}", sessionId, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会话关闭时尽量停止终端侧播放和采集,失败不阻断本地资源释放。
|
||||||
|
*/
|
||||||
|
private void stopTerminalAudio() {
|
||||||
|
try {
|
||||||
|
SpeakerCommand.StopSpeakerCommand.Request speakerStop = SpeakerCommand.StopSpeakerCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(speakerDeviceId))
|
||||||
|
.build();
|
||||||
|
speakerStub.withDeadlineAfter(HEARTBEAT_DEADLINE_MS, TimeUnit.MILLISECONDS).stopPlayback(speakerStop,
|
||||||
|
new EmptyStreamObserver<SpeakerCommand.StopSpeakerCommand.Feedback>("stop speaker", sessionId));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.debug("下发停止扬声器失败,sessionId={}", sessionId, t);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
MicrophoneCommand.StopMicRecordingCommand.Request micStop = MicrophoneCommand.StopMicRecordingCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(micDeviceId))
|
||||||
|
.build();
|
||||||
|
micStub.withDeadlineAfter(HEARTBEAT_DEADLINE_MS, TimeUnit.MILLISECONDS).stopRecord(micStop,
|
||||||
|
new EmptyStreamObserver<MicrophoneCommand.StopMicRecordingCommand.Feedback>("stop mic", sessionId));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.debug("下发停止麦克风失败,sessionId={}", sessionId, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeLocalResources() {
|
||||||
|
ScheduledFuture<?> sf = sendFuture;
|
||||||
|
if (sf != null) {
|
||||||
|
sf.cancel(false);
|
||||||
|
}
|
||||||
|
ScheduledFuture<?> hf = heartbeatFuture;
|
||||||
|
if (hf != null) {
|
||||||
|
hf.cancel(false);
|
||||||
|
}
|
||||||
|
browserFrameQueue.clear();
|
||||||
|
pendingBrowserBytes = new byte[0];
|
||||||
|
if (!sendExecutor.isShutdown()) {
|
||||||
|
sendExecutor.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logGrpcInboundFormatIfNeeded(long sequence, long timestampMs, Common.AudioData audio, byte[] pcm) {
|
||||||
|
if (sequence == 1 || sequence % 500 == 0) {
|
||||||
|
log.info("gRPC机器人上行音频格式,sessionId={},sampleRate={},channels={},bitsPerSample={},encoding={},frameSamples={},frameMs={},bytes={},sequence={},timestampMs={}",
|
||||||
|
sessionId,
|
||||||
|
audio.getSampleRate() == 0 ? SAMPLE_RATE : audio.getSampleRate(),
|
||||||
|
audio.getChannels() == 0 ? CHANNELS : audio.getChannels(),
|
||||||
|
BITS_PER_SAMPLE,
|
||||||
|
audio.getCodec() == null || audio.getCodec().length() == 0 ? CODEC : audio.getCodec(),
|
||||||
|
audio.getNbSamples() == 0 ? pcm.length / 2 : audio.getNbSamples(),
|
||||||
|
FRAME_MS,
|
||||||
|
pcm.length,
|
||||||
|
sequence,
|
||||||
|
timestampMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logGrpcOutboundFormatIfNeeded(long sequence, long timestampMs, byte[] frame) {
|
||||||
|
if (sequence == 1 || sequence % 500 == 0) {
|
||||||
|
log.info("gRPC浏览器下行音频格式,sessionId={},sampleRate={},channels={},bitsPerSample={},encoding={},frameSamples={},frameMs={},bytes={},sequence={},timestampMs={}",
|
||||||
|
sessionId, SAMPLE_RATE, CHANNELS, BITS_PER_SAMPLE, CODEC, FRAME_SAMPLES, FRAME_MS, frame.length, sequence, timestampMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logBrowserAudioStatsIfNeeded(String source) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
if (now - lastStatsLogAt < 5000L) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastStatsLogAt = now;
|
||||||
|
log.info("gRPC浏览器音频统计,source={},sessionId={},enqueued={},sent={},dropped={},queued={}",
|
||||||
|
source, sessionId, enqueued.get(), sent.get(), dropped.get(), browserFrameQueue.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logPcmStatsIfNeeded(String direction, long sequence, long timestampMs, byte[] pcm) {
|
||||||
|
if (sequence != 1 && sequence % 500 != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PcmStats stats = PcmStats.from(pcm);
|
||||||
|
log.info("PCM-STATS direction={} sessionId={} sequence={} timestampMs={} bytes={} samples={} rms={} peak={} zeroCrossRate={} firstSamples={}",
|
||||||
|
direction, sessionId, sequence, timestampMs, pcm.length, stats.samples, stats.rms, stats.peak, stats.zeroCrossRate, stats.firstSamples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class EmptyStreamObserver<T> implements StreamObserver<T> {
|
||||||
|
private final String action;
|
||||||
|
private final String sessionId;
|
||||||
|
|
||||||
|
private EmptyStreamObserver(String action, String sessionId) {
|
||||||
|
this.action = action;
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(T value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable t) {
|
||||||
|
log.debug("{} failed, sessionId={}", action, sessionId, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCompleted() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NamedThreadFactory implements ThreadFactory {
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private NamedThreadFactory(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread thread = new Thread(r, name);
|
||||||
|
thread.setDaemon(true);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PcmStats {
|
||||||
|
private final int samples;
|
||||||
|
private final long rms;
|
||||||
|
private final int peak;
|
||||||
|
private final String zeroCrossRate;
|
||||||
|
private final String firstSamples;
|
||||||
|
|
||||||
|
private PcmStats(int samples, long rms, int peak, String zeroCrossRate, String firstSamples) {
|
||||||
|
this.samples = samples;
|
||||||
|
this.rms = rms;
|
||||||
|
this.peak = peak;
|
||||||
|
this.zeroCrossRate = zeroCrossRate;
|
||||||
|
this.firstSamples = firstSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PcmStats from(byte[] pcm) {
|
||||||
|
int samples = pcm == null ? 0 : pcm.length / 2;
|
||||||
|
if (samples == 0) {
|
||||||
|
return new PcmStats(0, 0, 0, "0.0000", "[]");
|
||||||
|
}
|
||||||
|
long squareSum = 0L;
|
||||||
|
int peak = 0;
|
||||||
|
int zeroCross = 0;
|
||||||
|
int previous = 0;
|
||||||
|
StringBuilder first = new StringBuilder("[");
|
||||||
|
for (int i = 0; i < samples; i++) {
|
||||||
|
int lo = pcm[i * 2] & 0xff;
|
||||||
|
int hi = pcm[i * 2 + 1];
|
||||||
|
int value = (short) ((hi << 8) | lo);
|
||||||
|
int abs = Math.abs(value);
|
||||||
|
if (abs > peak) {
|
||||||
|
peak = abs;
|
||||||
|
}
|
||||||
|
squareSum += (long) value * value;
|
||||||
|
if (i > 0 && ((previous < 0 && value >= 0) || (previous >= 0 && value < 0))) {
|
||||||
|
zeroCross++;
|
||||||
|
}
|
||||||
|
previous = value;
|
||||||
|
if (i < 8) {
|
||||||
|
if (i > 0) {
|
||||||
|
first.append(',');
|
||||||
|
}
|
||||||
|
first.append(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
first.append(']');
|
||||||
|
long rms = (long) Math.sqrt(squareSum / (double) samples);
|
||||||
|
String zcr = String.format("%.4f", zeroCross / (double) samples);
|
||||||
|
return new PcmStats(samples, rms, peak, zcr, first.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -47,16 +47,21 @@ public class GrpcServiceManager {
|
|||||||
clientFactories.put(SystemServiceGrpc.SystemServiceBlockingStub.class, new GrpcClientFactory<>(SystemServiceGrpc::newBlockingStub));
|
clientFactories.put(SystemServiceGrpc.SystemServiceBlockingStub.class, new GrpcClientFactory<>(SystemServiceGrpc::newBlockingStub));
|
||||||
// 注册扬声器服务的 Stub
|
// 注册扬声器服务的 Stub
|
||||||
clientFactories.put(SpeakerServiceGrpc.SpeakerServiceBlockingStub.class, new GrpcClientFactory<>(SpeakerServiceGrpc::newBlockingStub));
|
clientFactories.put(SpeakerServiceGrpc.SpeakerServiceBlockingStub.class, new GrpcClientFactory<>(SpeakerServiceGrpc::newBlockingStub));
|
||||||
|
clientFactories.put(SpeakerServiceGrpc.SpeakerServiceStub.class, new GrpcClientFactory<>(SpeakerServiceGrpc::newStub));
|
||||||
// 注册麦克风服务的 Stub
|
// 注册麦克风服务的 Stub
|
||||||
clientFactories.put(MicPhoneServiceGrpc.MicPhoneServiceBlockingStub.class, new GrpcClientFactory<>(MicPhoneServiceGrpc::newBlockingStub));
|
clientFactories.put(MicPhoneServiceGrpc.MicPhoneServiceBlockingStub.class, new GrpcClientFactory<>(MicPhoneServiceGrpc::newBlockingStub));
|
||||||
|
clientFactories.put(MicPhoneServiceGrpc.MicPhoneServiceStub.class, new GrpcClientFactory<>(MicPhoneServiceGrpc::newStub));
|
||||||
// 注册机器人头部服务的 Stub
|
// 注册机器人头部服务的 Stub
|
||||||
clientFactories.put(BioHeadServiceGrpc.BioHeadServiceBlockingStub.class, new GrpcClientFactory<>(BioHeadServiceGrpc::newBlockingStub));
|
clientFactories.put(BioHeadServiceGrpc.BioHeadServiceBlockingStub.class, new GrpcClientFactory<>(BioHeadServiceGrpc::newBlockingStub));
|
||||||
// 注册机器人灵巧手服务的 Stub
|
// 注册机器人灵巧手服务的 Stub
|
||||||
clientFactories.put(DexHandServiceGrpc.DexHandServiceBlockingStub.class, new GrpcClientFactory<>(DexHandServiceGrpc::newBlockingStub));
|
clientFactories.put(DexHandServiceGrpc.DexHandServiceBlockingStub.class, new GrpcClientFactory<>(DexHandServiceGrpc::newBlockingStub));
|
||||||
clientFactories.put(DexHandServiceGrpc.DexHandServiceStub.class, new GrpcClientFactory<>(DexHandServiceGrpc::newStub));
|
clientFactories.put(DexHandServiceGrpc.DexHandServiceStub.class, new GrpcClientFactory<>(DexHandServiceGrpc::newStub));
|
||||||
// 注册机械臂服务的stub
|
// 注册机械臂服务的stub
|
||||||
clientFactories.put(HumanoidRobotServiceGrpc.HumanoidRobotServiceBlockingStub.class, new GrpcClientFactory<>(HumanoidRobotServiceGrpc::newBlockingStub));
|
clientFactories.put(ArmServiceGrpc.ArmServiceBlockingStub.class, new GrpcClientFactory<>(ArmServiceGrpc::newBlockingStub));
|
||||||
clientFactories.put(HlcServiceGrpc.HlcServiceBlockingStub.class, new GrpcClientFactory<>(HlcServiceGrpc::newBlockingStub));
|
clientFactories.put(HlcServiceGrpc.HlcServiceBlockingStub.class, new GrpcClientFactory<>(HlcServiceGrpc::newBlockingStub));
|
||||||
|
// 注册agv服务的stub
|
||||||
|
clientFactories.put(AgvServiceGrpc.AgvServiceBlockingStub.class, new GrpcClientFactory<>(AgvServiceGrpc::newBlockingStub));
|
||||||
|
// 注册机器人实时语音双向流服务的异步Stub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.cmvr.edge.client.model.agv;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV电池状态VO
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-07-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel("AGV电池状态")
|
||||||
|
public class EdgeAgvBatteryStatusVO {
|
||||||
|
|
||||||
|
@ApiModelProperty("电池电量百分比(0-100)")
|
||||||
|
private double batteryPercent;
|
||||||
|
|
||||||
|
@ApiModelProperty("电池电压(单位:伏特)")
|
||||||
|
private double voltage;
|
||||||
|
|
||||||
|
@ApiModelProperty("电池电流(单位:安培)")
|
||||||
|
private double current;
|
||||||
|
|
||||||
|
@ApiModelProperty("充电状态(true=充电中,false=未充电)")
|
||||||
|
private boolean charging;
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.cmvr.edge.client.model.agv;
|
||||||
|
|
||||||
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV 地图名称请求参数。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("AGV地图名称参数")
|
||||||
|
public class EdgeAgvMapNameVO extends EdgeCommonVO {
|
||||||
|
|
||||||
|
@NotEmpty(message = "地图名称不能为空")
|
||||||
|
@ApiModelProperty(value = "地图名称", required = true)
|
||||||
|
private String mapName;
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.cmvr.edge.client.model.agv;
|
||||||
|
|
||||||
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV 导航到指定坐标的请求参数。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("AGV导航到指定坐标参数")
|
||||||
|
public class EdgeAgvNavigateToPoseVO extends EdgeCommonVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "目标 X 坐标,单位:米", required = true)
|
||||||
|
private double x;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "目标 Y 坐标,单位:米", required = true)
|
||||||
|
private double y;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "目标朝向角,单位:弧度", required = true)
|
||||||
|
private double theta;
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.cmvr.edge.client.model.agv;
|
||||||
|
|
||||||
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV 导航到站点的请求参数。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("AGV导航到站点参数")
|
||||||
|
public class EdgeAgvNavigateToStationVO extends EdgeCommonVO {
|
||||||
|
|
||||||
|
@NotEmpty(message = "站点ID不能为空")
|
||||||
|
@ApiModelProperty(value = "站点ID", required = true)
|
||||||
|
private String stationId;
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.cmvr.edge.client.model.agv;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV导航任务结果VO
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-07-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel("AGV导航任务结果")
|
||||||
|
public class EdgeAgvNavigationResultVO {
|
||||||
|
|
||||||
|
@ApiModelProperty("返回码(0=成功)")
|
||||||
|
private int retCode;
|
||||||
|
|
||||||
|
@ApiModelProperty("错误信息")
|
||||||
|
private String errMsg;
|
||||||
|
|
||||||
|
@ApiModelProperty("任务ID")
|
||||||
|
private String taskId;
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.cmvr.edge.client.model.agv;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV机器人位置VO
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-07-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel("AGV机器人位置")
|
||||||
|
public class EdgeAgvRobotLocationVO {
|
||||||
|
|
||||||
|
@ApiModelProperty("X坐标(单位:米)")
|
||||||
|
private double x;
|
||||||
|
|
||||||
|
@ApiModelProperty("Y坐标(单位:米)")
|
||||||
|
private double y;
|
||||||
|
|
||||||
|
@ApiModelProperty("角度(单位:弧度)")
|
||||||
|
private double theta;
|
||||||
|
|
||||||
|
@ApiModelProperty("地图名称")
|
||||||
|
private String mapName;
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.cmvr.edge.client.model.agv;
|
||||||
|
|
||||||
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV 开始建图请求参数。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("AGV开始建图参数")
|
||||||
|
public class EdgeAgvStartMappingVO extends EdgeCommonVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "建图维度:0=未指定,1=2D,2=3D,3=2D+3D", required = true)
|
||||||
|
private int dimension;
|
||||||
|
|
||||||
|
@ApiModelProperty("地图名称,可为空")
|
||||||
|
private String mapName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "是否实时建图", required = true)
|
||||||
|
private boolean realTime;
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package com.cmvr.edge.client.model.agv;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV站点信息VO
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-07-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel("AGV站点信息")
|
||||||
|
public class EdgeAgvStationVO {
|
||||||
|
|
||||||
|
@ApiModelProperty("站点ID")
|
||||||
|
private String stationId;
|
||||||
|
|
||||||
|
@ApiModelProperty("站点名称")
|
||||||
|
private String stationName;
|
||||||
|
|
||||||
|
@ApiModelProperty("X坐标(单位:米)")
|
||||||
|
private double x;
|
||||||
|
|
||||||
|
@ApiModelProperty("Y坐标(单位:米)")
|
||||||
|
private double y;
|
||||||
|
|
||||||
|
@ApiModelProperty("角度(单位:弧度)")
|
||||||
|
private double theta;
|
||||||
|
|
||||||
|
@ApiModelProperty("站点类型")
|
||||||
|
private String stationType;
|
||||||
|
|
||||||
|
@ApiModelProperty("站点描述")
|
||||||
|
private String description;
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.cmvr.edge.client.model.agv;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV任务状态VO
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-07-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel("AGV任务状态")
|
||||||
|
public class EdgeAgvTaskStatusVO {
|
||||||
|
|
||||||
|
@ApiModelProperty("任务状态")
|
||||||
|
private int taskStatus;
|
||||||
|
|
||||||
|
@ApiModelProperty("当前站点ID")
|
||||||
|
private String currentStationId;
|
||||||
|
|
||||||
|
@ApiModelProperty("目标站点ID")
|
||||||
|
private String targetStationId;
|
||||||
|
|
||||||
|
@ApiModelProperty("已经过的站点数量")
|
||||||
|
private int passedStationCount;
|
||||||
|
|
||||||
|
@ApiModelProperty("剩余站点数量")
|
||||||
|
private int remainingStationCount;
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package com.cmvr.edge.client.model.agv;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV 上传地图请求参数。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("AGV上传地图参数")
|
||||||
|
public class EdgeAgvUploadMapVO extends EdgeAgvMapNameVO {
|
||||||
|
|
||||||
|
@NotEmpty(message = "地图内容不能为空")
|
||||||
|
@ApiModelProperty(value = "地图内容", required = true)
|
||||||
|
private String content;
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.cmvr.edge.client.model.agv;
|
||||||
|
|
||||||
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGV 速度控制请求参数。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("AGV速度控制参数")
|
||||||
|
public class EdgeAgvVelocityVO extends EdgeCommonVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "X 方向线速度,单位:m/s", required = true)
|
||||||
|
private double vx;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "Y 方向线速度,单位:m/s", required = true)
|
||||||
|
private double vy;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "角速度,单位:rad/s", required = true)
|
||||||
|
private double wz;
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.cmvr.edge.client.model.arm;
|
||||||
|
|
||||||
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机械臂标定零点参数。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("机械臂标定零点参数")
|
||||||
|
public class EdgeArmCalibrateZeroQVO extends EdgeCommonVO {
|
||||||
|
|
||||||
|
@NotEmpty(message = "关节名称不能为空")
|
||||||
|
@ApiModelProperty(value = "关节名称", required = true)
|
||||||
|
private String jointName;
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.cmvr.edge.client.model.arm;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机械臂笛卡尔位姿VO
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-07-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel("机械臂笛卡尔位姿")
|
||||||
|
public class EdgeArmCartesianPoseVO {
|
||||||
|
|
||||||
|
@ApiModelProperty("X轴坐标(单位:米)")
|
||||||
|
private double x;
|
||||||
|
|
||||||
|
@ApiModelProperty("Y轴坐标(单位:米)")
|
||||||
|
private double y;
|
||||||
|
|
||||||
|
@ApiModelProperty("Z轴坐标(单位:米)")
|
||||||
|
private double z;
|
||||||
|
|
||||||
|
@ApiModelProperty("RX旋转角度(单位:弧度)")
|
||||||
|
private double rx;
|
||||||
|
|
||||||
|
@ApiModelProperty("RY旋转角度(单位:弧度)")
|
||||||
|
private double ry;
|
||||||
|
|
||||||
|
@ApiModelProperty("RZ旋转角度(单位:弧度)")
|
||||||
|
private double rz;
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.cmvr.edge.client.model.arm;
|
||||||
|
|
||||||
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机械臂正向运动学计算VO
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
* @since 2026-07-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel("机械臂正向运动学计算参数")
|
||||||
|
public class EdgeArmForwardKinematicsVO extends EdgeCommonVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "关节位置数组(6个关节角度,单位:弧度)", required = true)
|
||||||
|
private double[] joints;
|
||||||
|
|
||||||
|
@ApiModelProperty("基座连杆名称")
|
||||||
|
private String baseLink;
|
||||||
|
|
||||||
|
@ApiModelProperty("末端执行器连杆名称")
|
||||||
|
private String eeLink;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user