生成代码工程

This commit is contained in:
root 2026-06-09 15:58:18 +08:00
parent 5c2aaae784
commit 5e063dba6d
37 changed files with 36026 additions and 2 deletions

138
README.md
View File

@ -1,3 +1,137 @@
# 求求了
# 战场态势与任务规划系统
暂无描述
## 项目简介
本项目实现战场态势与任务规划系统中**事件处理与任务生成模块EHTG** 与**任务方案管理软件TMS** 的核心后端服务。
### 核心功能
#### 事件处理与任务生成模块EHTG
- 事件接收与解析、数据清洗与标准化
- 高价值目标评估
- 任务模板匹配与任务草案生成
- 任务草案发送与重试机制
#### 任务方案管理软件TMS
- 集中式/分布式方案列表展示与排序
- 方案详情查看与多方案对比分析
- 方案重构与差异高亮
- 方案分发与执行状态监控
- 异常告警与人机环通知
## 技术栈
| 技术 | 版本 | 用途 |
|------|------|------|
| Java | 17 | 开发语言 |
| Spring Boot | 3.2.0 | 框架基础 |
| Maven | 3.8+ | 构建工具 |
| Knife4j + OpenAPI 3 | 4.5.0 | 接口文档与调试 |
## 快速启动
### 前置条件
- JDK 17+
- Maven 3.8+
### 编译运行
```bash
# 编译
mvn clean package
# 运行
mvn spring-boot:run
# 或直接运行 jar
java -jar target/battlefield-mission-system-1.0.0.jar
```
### 访问地址
| 服务 | 地址 |
|------|------|
| 应用主页 | http://localhost:8080 |
| Swagger 文档 | http://localhost:8080/swagger-ui/index.html |
| Knife4j 文档 | http://localhost:8080/doc.html |
## 项目结构
```
src/main/java/com/example/demo/
├── DemoApplication.java # 启动类
├── config/
│ └── OpenApiConfig.java # OpenAPI/Knife4j 配置
├── controller/
│ ├── HealthController.java # 健康检查
│ ├── EventController.java # 事件管理接口EHTG
│ ├── TaskController.java # 任务生成接口EHTG
│ └── SchemeController.java # 任务方案管理接口TMS
├── service/
│ ├── EventService.java # 事件处理服务
│ ├── TaskGenerationService.java # 任务生成服务
│ └── SchemeService.java # 任务方案管理服务
├── model/
│ ├── Event.java # 事件实体
│ ├── TaskTemplate.java # 任务模板实体
│ ├── TaskDraft.java # 任务草案实体
│ ├── TaskScheme.java # 任务方案实体
│ ├── enums/
│ │ ├── EventStatus.java # 事件状态枚举
│ │ ├── EventSourceType.java # 事件来源类型枚举
│ │ ├── ThreatLevel.java # 威胁等级枚举
│ │ └── SchemeStatus.java # 方案状态枚举
│ └── dto/
│ ├── EventDTO.java # 事件数据传输对象
│ ├── EventQueryDTO.java # 事件查询参数
│ ├── SchemeCompareDTO.java # 方案对比数据传输对象
│ └── ApiResponse.java # 统一响应封装
└── repository/
├── EventRepository.java # 事件仓储接口(内存实现)
├── TaskTemplateRepository.java # 任务模板仓储接口(内存实现)
├── TaskDraftRepository.java # 任务草案仓储接口(内存实现)
└── SchemeRepository.java # 方案仓储接口(内存实现)
src/test/java/com/example/demo/
├── EventServiceTest.java # 事件服务测试
├── TaskGenerationServiceTest.java # 任务生成服务测试
└── SchemeServiceTest.java # 方案管理服务测试
```
## API 概览
### 事件处理模块EHTG
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /api/v1/events | 接收原始事件 |
| GET | /api/v1/events | 查询事件列表 |
| GET | /api/v1/events/{id} | 查询事件详情 |
| PUT | /api/v1/events/{id}/process | 处理事件 |
### 任务生成模块EHTG
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /api/v1/tasks/generate | 基于事件生成任务草案 |
| GET | /api/v1/tasks/drafts | 查询任务草案列表 |
| GET | /api/v1/tasks/drafts/{id} | 查询任务草案详情 |
| POST | /api/v1/tasks/drafts/{id}/retry | 重试发送任务草案 |
### 任务方案管理模块TMS
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /api/v1/schemes | 查询方案列表(支持排序、分页) |
| GET | /api/v1/schemes/{id} | 查询方案详情 |
| POST | /api/v1/schemes/compare | 多方案对比分析 |
| POST | /api/v1/schemes/{id}/reconstruct | 方案重构 |
| POST | /api/v1/schemes/{id}/dispatch | 方案分发 |
| GET | /api/v1/schemes/{id}/execution-status | 查询执行状态 |
## 设计说明
### 当前实现
- **数据层**:采用内存 `ConcurrentHashMap` 存储,所有数据在应用启动时初始化示例数据
- **后续扩展**:预留了 `Repository` 接口层,后续可替换为 MyBatis/JPA 等数据库实现
- **错误处理**:全局统一异常处理,返回标准错误格式
### 对应需求追溯
所有业务方法均通过 Javadoc `@requirement` 标签关联需求,可追溯至软件需求规格说明。

32200
events.ndjson Normal file

File diff suppressed because one or more lines are too long

61
generation.json Normal file

File diff suppressed because one or more lines are too long

85
pom.xml Normal file
View File

@ -0,0 +1,85 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>battlefield-mission-system</artifactId>
<version>1.0.0</version>
<name>战场态势与任务规划系统</name>
<description>战场态势与任务规划系统 - 事件处理与任务生成模块(EHTG) + 任务方案管理软件(TMS)</description>
<properties>
<java.version>17</java.version>
<knife4j.version>4.5.0</knife4j.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Knife4j OpenAPI3 (Spring Boot 3.x Jakarta) -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,18 @@
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 战场态势与任务规划系统 - 启动类
* <p>
* 集成事件处理与任务生成模块EHTG和任务方案管理软件TMS的核心后端服务
* </p>
*/
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

View File

@ -0,0 +1,52 @@
package com.example.demo.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* OpenAPI / Knife4j 配置类
* <p>
* 配置 Swagger/OpenAPI 接口文档集成 Knife4j 增强UI
* 访问地址http://localhost:8080/doc.html
* </p>
*/
@Configuration
public class OpenApiConfig {
/**
* 自定义 OpenAPI 信息
*
* @return OpenAPI 实例
*/
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("战场态势与任务规划系统 API")
.version("1.0.0")
.description("""
战场态势与任务规划系统 API 文档
集成以下两大核心模块
**1. 事件处理与任务生成模块EHTG**
- 事件接收与解析数据清洗与标准化
- 高价值目标评估与任务模板匹配
- 任务草案生成与发送重试
**2. 任务方案管理软件TMS**
- 集中式/分布式方案列表展示与排序
- 方案详情查看与多方案对比分析
- 方案重构与版本关联追溯
- 方案分发与执行状态监控
""")
.contact(new Contact()
.name("开发团队")
.email("dev@example.com"))
.license(new License()
.name("保密")
.url("")));
}
}

View File

@ -0,0 +1,137 @@
package com.example.demo.controller;
import com.example.demo.model.Event;
import com.example.demo.model.dto.ApiResponse;
import com.example.demo.model.dto.EventDTO;
import com.example.demo.model.dto.EventQueryDTO;
import com.example.demo.model.enums.EventSourceType;
import com.example.demo.model.enums.EventStatus;
import com.example.demo.model.enums.ThreatLevel;
import com.example.demo.service.EventService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* 事件管理控制器
* <p>
* 提供事件接收查询处理等 RESTful API 接口
* 对应外部接口 IF-01 / SRS-EHTG_I_EVT IF-02 / SRS-EHTG_I_UI
* </p>
*
* @requirement(name="事件接收与解析", id="SRS-EHTG-01")
* 通过HTTP POST接收上游传感器的原始事件数据
*
* @requirement(name="前端可视化展示", id="SRS-EHTG-04")
* 提供Web界面展示事件列表支持排序筛选和操作反馈
*/
@Tag(name = "事件管理 (EHTG)", description = "事件处理与任务生成模块 - 事件接收、查询、处理接口")
@RestController
@RequestMapping("/api/v1/events")
public class EventController {
private static final Logger log = LoggerFactory.getLogger(EventController.class);
private final EventService eventService;
public EventController(EventService eventService) {
this.eventService = eventService;
}
/**
* 接收原始事件
* <p>
* 对应外部接口 IF-01接收上游传感器融合模块的原始事件数据
* </p>
*
* @param eventDTO 事件数据
* @return 处理后的标准化事件
*/
@Operation(summary = "接收原始事件", description = "接收上游传感器融合模块的原始事件数据,执行数据清洗与标准化")
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<Event> receiveEvent(@Valid @RequestBody EventDTO eventDTO) {
log.info("接收到事件请求,来源: {}", eventDTO.getSourceType());
Event rawEvent = convertToEvent(eventDTO);
Event processedEvent = eventService.receiveEvent(rawEvent);
return ApiResponse.success("事件接收并处理成功", processedEvent);
}
/**
* 查询事件列表
* <p>
* 支持按状态筛选按字段排序和分页
* </p>
*
* @param query 查询参数
* @return 事件列表
*/
@Operation(summary = "查询事件列表", description = "查询事件列表,支持状态筛选、排序和分页")
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<List<Event>> listEvents(@Valid EventQueryDTO query) {
List<Event> events = eventService.queryEvents(query);
return ApiResponse.success(events);
}
/**
* 查询事件详情
*
* @param eventId 事件ID
* @return 事件详情
*/
@Operation(summary = "查询事件详情", description = "根据事件ID查询事件详细信息")
@GetMapping(value = "/{eventId}", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<Event> getEvent(@Parameter(description = "事件ID") @PathVariable String eventId) {
Optional<Event> eventOpt = eventService.getEventById(eventId);
return eventOpt.map(ApiResponse::success)
.orElseGet(() -> ApiResponse.error(404, "事件不存在: " + eventId));
}
/**
* 处理事件更新状态
*
* @param eventId 事件ID
* @param status 新状态
* @return 更新后的事件
*/
@Operation(summary = "处理事件", description = "更新事件处理状态")
@PutMapping(value = "/{eventId}/process", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<Event> processEvent(
@Parameter(description = "事件ID") @PathVariable String eventId,
@Parameter(description = "目标状态PENDING / PROCESSING / COMPLETED / IGNORED / ERROR")
@RequestParam String status) {
EventStatus eventStatus = EventStatus.valueOf(status.toUpperCase());
Optional<Event> updated = eventService.updateEventStatus(eventId, eventStatus);
return updated.map(ApiResponse::success)
.orElseGet(() -> ApiResponse.error(404, "事件不存在: " + eventId));
}
/**
* DTO 转换为实体
*/
private Event convertToEvent(EventDTO dto) {
Event event = new Event();
event.setEventId(dto.getEventId());
event.setSourceType(dto.getSourceType());
event.setOccurTime(dto.getOccurTime());
event.setLocation(dto.getLocation());
event.setConfidence(dto.getConfidence());
event.setThreatLevel(dto.getThreatLevel());
event.setEventType(dto.getEventType());
event.setStatus(EventStatus.PENDING);
event.setCreateTime(LocalDateTime.now());
event.setUpdateTime(LocalDateTime.now());
return event;
}
}

View File

@ -0,0 +1,37 @@
package com.example.demo.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 健康检查控制器
* <p>
* 提供系统健康检查和运行状态信息
* </p>
*/
@Tag(name = "系统健康检查", description = "系统运行状态与健康检查接口")
@RestController
public class HealthController {
/**
* 健康检查端点
*
* @return 系统健康状态
*/
@Operation(summary = "健康检查", description = "返回系统运行状态信息,包括服务状态、运行时间等")
@GetMapping("/api/health")
public Map<String, Object> health() {
Map<String, Object> status = new LinkedHashMap<>();
status.put("status", "UP");
status.put("service", "战场态势与任务规划系统");
status.put("timestamp", LocalDateTime.now().toString());
status.put("version", "1.0.0");
return status;
}
}

View File

@ -0,0 +1,160 @@
package com.example.demo.controller;
import com.example.demo.model.TaskScheme;
import com.example.demo.model.dto.ApiResponse;
import com.example.demo.model.dto.SchemeCompareDTO;
import com.example.demo.service.SchemeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* 任务方案管理控制器
* <p>
* 提供集中式/分布式任务方案的全生命周期管理 RESTful API
* 对应外部接口 SRS-TMS_I_UISRS-TMS_I_PlanningSRS-TMS_I_Execution
* </p>
*
* @requirement(name="集中式/分布式方案列表展示", id="SRS-TMS-01")
* 以表格或卡片形式展示所有可用任务方案支持分页加载
*
* @requirement(name="方案详情查看", id="SRS-TMS-03")
* 展示兵力部署行动路线时间节点等详细信息
*
* @requirement(name="多方案对比分析", id="SRS-TMS-04")
* 支持最多5个方案的关键指标并列比较
*
* @requirement(name="方案分发驱动", id="SRS-TMS-08")
* 将选定方案解析为指令集下发至指定执行节点
*
* @requirement(name="执行状态监控", id="SRS-TMS-10")
* 实时聚合子任务进度展示整体完成率与当前状态
*/
@Tag(name = "任务方案管理 (TMS)", description = "任务方案管理软件 - 方案列表、详情、对比、重构、分发、执行监控接口")
@RestController
@RequestMapping("/api/v1/schemes")
public class SchemeController {
private final SchemeService schemeService;
public SchemeController(SchemeService schemeService) {
this.schemeService = schemeService;
}
/**
* 查询方案列表
*
* @param sortField 排序字段createTime / priority / successRate / estimatedDuration / estimatedLossRatio
* @param sortDirection 排序方向asc / desc
* @param page 页码
* @param size 每页条数
* @return 方案列表
*/
@Operation(summary = "查询方案列表", description = "查询所有可用任务方案,支持自定义排序和分页")
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<List<TaskScheme>> listSchemes(
@Parameter(description = "排序字段") @RequestParam(required = false, defaultValue = "createTime") String sortField,
@Parameter(description = "排序方向") @RequestParam(required = false, defaultValue = "desc") String sortDirection,
@Parameter(description = "页码") @RequestParam(required = false, defaultValue = "0") int page,
@Parameter(description = "每页条数") @RequestParam(required = false, defaultValue = "20") int size) {
List<TaskScheme> schemes = schemeService.listSchemes(sortField, sortDirection, page, size);
return ApiResponse.success(schemes);
}
/**
* 查询方案详情
*
* @param schemeId 方案ID
* @return 方案详情
*/
@Operation(summary = "查询方案详情", description = "展示兵力部署、行动路线、时间节点等详细信息及算法溯源")
@GetMapping(value = "/{schemeId}", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<TaskScheme> getSchemeDetail(
@Parameter(description = "方案ID") @PathVariable String schemeId) {
Optional<TaskScheme> scheme = schemeService.getSchemeDetail(schemeId);
return scheme.map(ApiResponse::success)
.orElseGet(() -> ApiResponse.error(404, "方案不存在: " + schemeId));
}
/**
* 多方案对比分析
*
* @param compareDTO 对比参数最多5个方案
* @return 对比结果
*/
@Operation(summary = "多方案对比分析", description = "支持最多5个方案的关键指标并列比较耗时、战损比、成功率等")
@PostMapping(value = "/compare", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<Map<String, Object>> compareSchemes(@Valid @RequestBody SchemeCompareDTO compareDTO) {
try {
Map<String, Object> result = schemeService.compareSchemes(compareDTO);
return ApiResponse.success(result);
} catch (IllegalArgumentException e) {
return ApiResponse.badRequest(e.getMessage());
}
}
/**
* 方案重构
*
* @param schemeId 原方案ID
* @param newConstraints 新约束条件JSON格式
* @return 重构后的新方案
*/
@Operation(summary = "方案重构", description = "基于新约束条件重新生成或调整现有方案,并保留版本关联追溯")
@PostMapping(value = "/{schemeId}/reconstruct", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<TaskScheme> reconstructScheme(
@Parameter(description = "原方案ID") @PathVariable String schemeId,
@Parameter(description = "新约束条件JSON格式") @RequestBody String newConstraints) {
try {
TaskScheme newScheme = schemeService.reconstructScheme(schemeId, newConstraints);
return ApiResponse.success("方案重构成功", newScheme);
} catch (IllegalArgumentException e) {
return ApiResponse.badRequest(e.getMessage());
}
}
/**
* 方案分发
*
* @param schemeId 方案ID
* @param targetNode 目标执行节点
* @return 分发结果
*/
@Operation(summary = "方案分发", description = "将选定方案解析为指令集,下发至指定执行节点")
@PostMapping(value = "/{schemeId}/dispatch", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<Map<String, Object>> dispatchScheme(
@Parameter(description = "方案ID") @PathVariable String schemeId,
@Parameter(description = "目标执行节点") @RequestParam String targetNode) {
try {
Map<String, Object> result = schemeService.dispatchScheme(schemeId, targetNode);
return ApiResponse.success("方案分发成功", result);
} catch (IllegalArgumentException e) {
return ApiResponse.badRequest(e.getMessage());
}
}
/**
* 查询方案执行状态
*
* @param schemeId 方案ID
* @return 执行状态
*/
@Operation(summary = "查询执行状态", description = "实时查询方案执行进度、子任务状态及整体完成率")
@GetMapping(value = "/{schemeId}/execution-status", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<Map<String, Object>> getExecutionStatus(
@Parameter(description = "方案ID") @PathVariable String schemeId) {
try {
Map<String, Object> status = schemeService.getExecutionStatus(schemeId);
return ApiResponse.success(status);
} catch (IllegalArgumentException e) {
return ApiResponse.badRequest(e.getMessage());
}
}
}

View File

@ -0,0 +1,118 @@
package com.example.demo.controller;
import com.example.demo.model.TaskDraft;
import com.example.demo.model.dto.ApiResponse;
import com.example.demo.service.TaskGenerationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
/**
* 任务生成控制器
* <p>
* 提供任务草案生成查询发送与重试等 RESTful API 接口
* 对应外部接口 IF-03 / SRS-EHTG_O_TSK
* </p>
*
* @requirement(name="任务模板匹配与生成", id="SRS-EHTG-06")
* 结合知识库中的任务模板自动生成符合标准的任务草案
*
* @requirement(name="任务草案发送与重试机制", id="SRS-EHTG-07")
* 向下游任务规划引擎发送请求失败时自动加入本地重试队列
*/
@Tag(name = "任务生成 (EHTG)", description = "事件处理与任务生成模块 - 任务草案生成、发送与重试接口")
@RestController
@RequestMapping("/api/v1/tasks")
public class TaskController {
private final TaskGenerationService taskGenerationService;
public TaskController(TaskGenerationService taskGenerationService) {
this.taskGenerationService = taskGenerationService;
}
/**
* 基于事件生成任务草案
*
* @param eventId 事件ID
* @return 生成的任务草案
*/
@Operation(summary = "生成任务草案", description = "基于事件评估结果,匹配任务模板并生成任务草案")
@PostMapping(value = "/generate", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<TaskDraft> generateTaskDraft(
@Parameter(description = "事件ID") @RequestParam String eventId) {
try {
TaskDraft draft = taskGenerationService.generateTaskDraft(eventId);
return ApiResponse.success("任务草案生成成功", draft);
} catch (IllegalArgumentException | IllegalStateException e) {
return ApiResponse.badRequest(e.getMessage());
}
}
/**
* 查询任务草案列表
*
* @return 草案列表
*/
@Operation(summary = "查询任务草案列表", description = "查询所有已生成的任务草案")
@GetMapping(value = "/drafts", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<List<TaskDraft>> listDrafts() {
return ApiResponse.success(taskGenerationService.getAllDrafts());
}
/**
* 查询任务草案详情
*
* @param draftId 草案ID
* @return 草案详情
*/
@Operation(summary = "查询任务草案详情", description = "根据草案ID查询任务草案详细信息")
@GetMapping(value = "/drafts/{draftId}", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<TaskDraft> getDraft(
@Parameter(description = "草案ID") @PathVariable String draftId) {
Optional<TaskDraft> draft = taskGenerationService.getDraftById(draftId);
return draft.map(ApiResponse::success)
.orElseGet(() -> ApiResponse.error(404, "任务草案不存在: " + draftId));
}
/**
* 发送任务草案到下游引擎
*
* @param draftId 草案ID
* @return 发送结果
*/
@Operation(summary = "发送任务草案", description = "将任务草案发送至下游任务规划引擎")
@PostMapping(value = "/drafts/{draftId}/send", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<String> sendDraft(
@Parameter(description = "草案ID") @PathVariable String draftId) {
boolean success = taskGenerationService.sendTaskDraft(draftId);
if (success) {
return ApiResponse.success("任务草案发送成功", draftId);
} else {
return ApiResponse.error(500, "任务草案发送失败,已加入重试队列");
}
}
/**
* 重试发送失败的任务草案
*
* @param draftId 草案ID
* @return 重试结果
*/
@Operation(summary = "重试发送任务草案", description = "重试发送之前失败的任务草案")
@PostMapping(value = "/drafts/{draftId}/retry", produces = MediaType.APPLICATION_JSON_VALUE)
public ApiResponse<String> retrySendDraft(
@Parameter(description = "草案ID") @PathVariable String draftId) {
boolean success = taskGenerationService.retrySendDraft(draftId);
if (success) {
return ApiResponse.success("任务草案重试发送成功", draftId);
} else {
return ApiResponse.error(500, "任务草案重试发送失败");
}
}
}

View File

@ -0,0 +1,145 @@
package com.example.demo.model;
import com.example.demo.model.enums.EventSourceType;
import com.example.demo.model.enums.EventStatus;
import com.example.demo.model.enums.ThreatLevel;
import java.time.LocalDateTime;
/**
* 事件实体模型
* <p>
* 对应数据库表 T_EVENT_INFO表示从传感器接收到的原始事件
* 经过数据清洗与标准化后形成的内部表示
* </p>
*/
public class Event {
/** 事件唯一标识全局唯一ID */
private String eventId;
/** 事件来源类型1-雷达, 2-光电 */
private EventSourceType sourceType;
/** 事件发生时间,精确到毫秒 */
private LocalDateTime occurTime;
/** 目标经纬度JSON格式存储如 {"lng": 116.397, "lat": 39.908} */
private String location;
/** 事件置信度范围0.0~1.0 */
private double confidence;
/** 处理状态码0-待处理, 1-已完成 */
private EventStatus status;
/** 威胁等级 */
private ThreatLevel threatLevel;
/** 事件类型:临机/规划 */
private String eventType;
/** 创建时间,默认系统当前时间 */
private LocalDateTime createTime;
/** 更新时间 */
private LocalDateTime updateTime;
public Event() {
}
public Event(String eventId, EventSourceType sourceType, LocalDateTime occurTime,
String location, double confidence, EventStatus status,
ThreatLevel threatLevel, String eventType) {
this.eventId = eventId;
this.sourceType = sourceType;
this.occurTime = occurTime;
this.location = location;
this.confidence = confidence;
this.status = status;
this.threatLevel = threatLevel;
this.eventType = eventType;
this.createTime = LocalDateTime.now();
this.updateTime = LocalDateTime.now();
}
public String getEventId() {
return eventId;
}
public void setEventId(String eventId) {
this.eventId = eventId;
}
public EventSourceType getSourceType() {
return sourceType;
}
public void setSourceType(EventSourceType sourceType) {
this.sourceType = sourceType;
}
public LocalDateTime getOccurTime() {
return occurTime;
}
public void setOccurTime(LocalDateTime occurTime) {
this.occurTime = occurTime;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public double getConfidence() {
return confidence;
}
public void setConfidence(double confidence) {
this.confidence = confidence;
}
public EventStatus getStatus() {
return status;
}
public void setStatus(EventStatus status) {
this.status = status;
}
public ThreatLevel getThreatLevel() {
return threatLevel;
}
public void setThreatLevel(ThreatLevel threatLevel) {
this.threatLevel = threatLevel;
}
public String getEventType() {
return eventType;
}
public void setEventType(String eventType) {
this.eventType = eventType;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
}

View File

@ -0,0 +1,139 @@
package com.example.demo.model;
import java.time.LocalDateTime;
/**
* 任务草案实体模型
* <p>
* 表示基于事件评估后生成的作战任务草案
* 准备下发至任务规划引擎进行详细规划
* </p>
*/
public class TaskDraft {
/** 任务草案唯一标识 */
private String draftId;
/** 关联的事件ID */
private String eventId;
/** 使用的模板ID */
private String templateId;
/** 任务草案标题 */
private String title;
/** 任务草案内容JSON格式 */
private String content;
/** 目标价值评分 */
private double targetValueScore;
/** 发送状态0-未发送, 1-已发送, 2-发送失败 */
private int sendStatus;
/** 发送重试次数 */
private int retryCount;
/** 创建时间 */
private LocalDateTime createTime;
/** 最后发送时间 */
private LocalDateTime lastSendTime;
public TaskDraft() {
}
public TaskDraft(String draftId, String eventId, String templateId, String title,
String content, double targetValueScore) {
this.draftId = draftId;
this.eventId = eventId;
this.templateId = templateId;
this.title = title;
this.content = content;
this.targetValueScore = targetValueScore;
this.sendStatus = 0;
this.retryCount = 0;
this.createTime = LocalDateTime.now();
}
public String getDraftId() {
return draftId;
}
public void setDraftId(String draftId) {
this.draftId = draftId;
}
public String getEventId() {
return eventId;
}
public void setEventId(String eventId) {
this.eventId = eventId;
}
public String getTemplateId() {
return templateId;
}
public void setTemplateId(String templateId) {
this.templateId = templateId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public double getTargetValueScore() {
return targetValueScore;
}
public void setTargetValueScore(double targetValueScore) {
this.targetValueScore = targetValueScore;
}
public int getSendStatus() {
return sendStatus;
}
public void setSendStatus(int sendStatus) {
this.sendStatus = sendStatus;
}
public int getRetryCount() {
return retryCount;
}
public void setRetryCount(int retryCount) {
this.retryCount = retryCount;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getLastSendTime() {
return lastSendTime;
}
public void setLastSendTime(LocalDateTime lastSendTime) {
this.lastSendTime = lastSendTime;
}
}

View File

@ -0,0 +1,257 @@
package com.example.demo.model;
import com.example.demo.model.enums.SchemeStatus;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 任务方案实体模型
* <p>
* 表示经过任务规划引擎生成的作战任务方案
* 包含兵力部署行动路线时间节点等详细信息
* </p>
*/
public class TaskScheme {
/** 方案唯一标识 */
private String schemeId;
/** 方案名称 */
private String schemeName;
/** 方案类型:集中式/分布式 */
private String schemeType;
/** 关联事件ID */
private String eventId;
/** 关联任务草案ID */
private String draftId;
/** 方案状态 */
private SchemeStatus status;
/** 方案优先级1-10数值越高优先级越高 */
private int priority;
/** 预计耗时(分钟) */
private int estimatedDuration;
/** 预计战损比0.0~1.0 */
private double estimatedLossRatio;
/** 方案成功率0.0~1.0 */
private double successRate;
/** 兵力部署详情JSON格式 */
private String deploymentDetail;
/** 行动路线JSON格式 */
private String routeDetail;
/** 时间节点JSON格式 */
private String timelineDetail;
/** 算法溯源信息AI生成路径、优化过程 */
private String algorithmTrace;
/** 父方案ID重构时关联旧版本 */
private String parentSchemeId;
/** 版本号 */
private int version;
/** 执行进度百分比0~100 */
private int executionProgress;
/** 子任务状态列表JSON格式 */
private String subTaskStatus;
/** 创建时间 */
private LocalDateTime createTime;
/** 更新时间 */
private LocalDateTime updateTime;
public TaskScheme() {
}
public TaskScheme(String schemeId, String schemeName, String schemeType,
SchemeStatus status, int priority, int estimatedDuration,
double estimatedLossRatio, double successRate) {
this.schemeId = schemeId;
this.schemeName = schemeName;
this.schemeType = schemeType;
this.status = status;
this.priority = priority;
this.estimatedDuration = estimatedDuration;
this.estimatedLossRatio = estimatedLossRatio;
this.successRate = successRate;
this.version = 1;
this.executionProgress = 0;
this.createTime = LocalDateTime.now();
this.updateTime = LocalDateTime.now();
}
public String getSchemeId() {
return schemeId;
}
public void setSchemeId(String schemeId) {
this.schemeId = schemeId;
}
public String getSchemeName() {
return schemeName;
}
public void setSchemeName(String schemeName) {
this.schemeName = schemeName;
}
public String getSchemeType() {
return schemeType;
}
public void setSchemeType(String schemeType) {
this.schemeType = schemeType;
}
public String getEventId() {
return eventId;
}
public void setEventId(String eventId) {
this.eventId = eventId;
}
public String getDraftId() {
return draftId;
}
public void setDraftId(String draftId) {
this.draftId = draftId;
}
public SchemeStatus getStatus() {
return status;
}
public void setStatus(SchemeStatus status) {
this.status = status;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public int getEstimatedDuration() {
return estimatedDuration;
}
public void setEstimatedDuration(int estimatedDuration) {
this.estimatedDuration = estimatedDuration;
}
public double getEstimatedLossRatio() {
return estimatedLossRatio;
}
public void setEstimatedLossRatio(double estimatedLossRatio) {
this.estimatedLossRatio = estimatedLossRatio;
}
public double getSuccessRate() {
return successRate;
}
public void setSuccessRate(double successRate) {
this.successRate = successRate;
}
public String getDeploymentDetail() {
return deploymentDetail;
}
public void setDeploymentDetail(String deploymentDetail) {
this.deploymentDetail = deploymentDetail;
}
public String getRouteDetail() {
return routeDetail;
}
public void setRouteDetail(String routeDetail) {
this.routeDetail = routeDetail;
}
public String getTimelineDetail() {
return timelineDetail;
}
public void setTimelineDetail(String timelineDetail) {
this.timelineDetail = timelineDetail;
}
public String getAlgorithmTrace() {
return algorithmTrace;
}
public void setAlgorithmTrace(String algorithmTrace) {
this.algorithmTrace = algorithmTrace;
}
public String getParentSchemeId() {
return parentSchemeId;
}
public void setParentSchemeId(String parentSchemeId) {
this.parentSchemeId = parentSchemeId;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public int getExecutionProgress() {
return executionProgress;
}
public void setExecutionProgress(int executionProgress) {
this.executionProgress = executionProgress;
}
public String getSubTaskStatus() {
return subTaskStatus;
}
public void setSubTaskStatus(String subTaskStatus) {
this.subTaskStatus = subTaskStatus;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
}

View File

@ -0,0 +1,102 @@
package com.example.demo.model;
/**
* 任务模板实体模型
* <p>
* 对应数据库表 T_TASK_TEMPLATE存储任务生成的模板定义
* 模板包含目标类型匹配规则任务逻辑定义等内容
* </p>
*/
public class TaskTemplate {
/** 模板唯一标识全局唯一ID */
private String templateId;
/** 适用目标类型,关联目标分类 */
private int targetType;
/** 模板内容XML存储任务逻辑定义 */
private String contentXml;
/** 版本号,如 V1.0 */
private String version;
/** 启用状态:是否启用该模板 */
private boolean active;
/** 模板名称 */
private String templateName;
/** 模板描述 */
private String description;
public TaskTemplate() {
}
public TaskTemplate(String templateId, int targetType, String contentXml,
String version, boolean active, String templateName, String description) {
this.templateId = templateId;
this.targetType = targetType;
this.contentXml = contentXml;
this.version = version;
this.active = active;
this.templateName = templateName;
this.description = description;
}
public String getTemplateId() {
return templateId;
}
public void setTemplateId(String templateId) {
this.templateId = templateId;
}
public int getTargetType() {
return targetType;
}
public void setTargetType(int targetType) {
this.targetType = targetType;
}
public String getContentXml() {
return contentXml;
}
public void setContentXml(String contentXml) {
this.contentXml = contentXml;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public String getTemplateName() {
return templateName;
}
public void setTemplateName(String templateName) {
this.templateName = templateName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View File

@ -0,0 +1,102 @@
package com.example.demo.model.dto;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* 统一API响应封装
* <p>
* 所有接口统一返回此格式包含状态码消息和数据
* </p>
*
* @param <T> 数据类型
*/
@Schema(description = "统一API响应")
public class ApiResponse<T> {
@Schema(description = "状态码200表示成功")
private int code;
@Schema(description = "响应消息")
private String message;
@Schema(description = "响应数据")
private T data;
private ApiResponse() {
}
private ApiResponse(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
/**
* 成功响应
*
* @param data 数据
* @param <T> 数据类型
* @return API响应
*/
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(200, "操作成功", data);
}
/**
* 成功响应带自定义消息
*
* @param message 消息
* @param data 数据
* @param <T> 数据类型
* @return API响应
*/
public static <T> ApiResponse<T> success(String message, T data) {
return new ApiResponse<>(200, message, data);
}
/**
* 失败响应
*
* @param code 状态码
* @param message 错误消息
* @param <T> 数据类型
* @return API响应
*/
public static <T> ApiResponse<T> error(int code, String message) {
return new ApiResponse<>(code, message, null);
}
/**
* 参数错误响应
*
* @param message 错误消息
* @param <T> 数据类型
* @return API响应
*/
public static <T> ApiResponse<T> badRequest(String message) {
return new ApiResponse<>(400, message, null);
}
/**
* 服务内部错误响应
*
* @param message 错误消息
* @param <T> 数据类型
* @return API响应
*/
public static <T> ApiResponse<T> internalError(String message) {
return new ApiResponse<>(500, message, null);
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public T getData() {
return data;
}
}

View File

@ -0,0 +1,119 @@
package com.example.demo.model.dto;
import com.example.demo.model.enums.EventSourceType;
import com.example.demo.model.enums.ThreatLevel;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;
/**
* 事件数据传输对象
* <p>
* 用于API请求和响应中传输事件数据
* </p>
*/
@Schema(description = "事件数据传输对象")
public class EventDTO {
@Schema(description = "事件唯一标识")
private String eventId;
@Schema(description = "事件来源类型RADAR / OPTOELECTRONIC / ELECTRONIC_RECON / COMMUNICATION_INTEL")
private EventSourceType sourceType;
@Schema(description = "事件发生时间格式yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime occurTime;
@Schema(description = "目标经纬度JSON格式")
private String location;
@Schema(description = "事件置信度0.0~1.0")
private double confidence;
@Schema(description = "威胁等级LOW / MEDIUM / HIGH / CRITICAL")
private ThreatLevel threatLevel;
@Schema(description = "事件类型:临机/规划")
private String eventType;
@Schema(description = "处理状态")
private String status;
@Schema(description = "创建时间")
private LocalDateTime createTime;
public EventDTO() {
}
public String getEventId() {
return eventId;
}
public void setEventId(String eventId) {
this.eventId = eventId;
}
public EventSourceType getSourceType() {
return sourceType;
}
public void setSourceType(EventSourceType sourceType) {
this.sourceType = sourceType;
}
public LocalDateTime getOccurTime() {
return occurTime;
}
public void setOccurTime(LocalDateTime occurTime) {
this.occurTime = occurTime;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public double getConfidence() {
return confidence;
}
public void setConfidence(double confidence) {
this.confidence = confidence;
}
public ThreatLevel getThreatLevel() {
return threatLevel;
}
public void setThreatLevel(ThreatLevel threatLevel) {
this.threatLevel = threatLevel;
}
public String getEventType() {
return eventType;
}
public void setEventType(String eventType) {
this.eventType = eventType;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
}

View File

@ -0,0 +1,143 @@
package com.example.demo.model.dto;
import com.example.demo.model.enums.EventSourceType;
import com.example.demo.model.enums.ThreatLevel;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* 事件查询/接收参数DTO
* <p>
* 用于接收上游传感器的事件数据或前端查询参数
* </p>
*/
@Schema(description = "事件接收/查询参数")
public class EventQueryDTO {
@Schema(description = "事件来源类型")
private EventSourceType sourceType;
@Schema(description = "事件发生时间")
private LocalDateTime occurTime;
@Schema(description = "目标经纬度JSON格式")
private String location;
@Schema(description = "事件置信度0.0~1.0")
@Min(0) @Max(1)
private double confidence;
@Schema(description = "威胁等级")
private ThreatLevel threatLevel;
@Schema(description = "事件类型")
private String eventType;
@Schema(description = "处理状态关键字过滤")
private String statusFilter;
@Schema(description = "排序字段createTime / occurTime / threatLevel / confidence")
private String sortField;
@Schema(description = "排序方向asc / desc")
private String sortDirection;
@Schema(description = "页码从0开始")
private int page;
@Schema(description = "每页条数")
private int size;
public EventSourceType getSourceType() {
return sourceType;
}
public void setSourceType(EventSourceType sourceType) {
this.sourceType = sourceType;
}
public LocalDateTime getOccurTime() {
return occurTime;
}
public void setOccurTime(LocalDateTime occurTime) {
this.occurTime = occurTime;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public double getConfidence() {
return confidence;
}
public void setConfidence(double confidence) {
this.confidence = confidence;
}
public ThreatLevel getThreatLevel() {
return threatLevel;
}
public void setThreatLevel(ThreatLevel threatLevel) {
this.threatLevel = threatLevel;
}
public String getEventType() {
return eventType;
}
public void setEventType(String eventType) {
this.eventType = eventType;
}
public String getStatusFilter() {
return statusFilter;
}
public void setStatusFilter(String statusFilter) {
this.statusFilter = statusFilter;
}
public String getSortField() {
return sortField;
}
public void setSortField(String sortField) {
this.sortField = sortField;
}
public String getSortDirection() {
return sortDirection;
}
public void setSortDirection(String sortDirection) {
this.sortDirection = sortDirection;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}

View File

@ -0,0 +1,37 @@
package com.example.demo.model.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
/**
* 方案对比分析数据传输对象
* <p>
* 用于接收前端多方案对比请求支持最多5个方案的关键指标并列比较
* </p>
*/
@Schema(description = "方案对比分析请求参数")
public class SchemeCompareDTO {
@Schema(description = "待对比的方案ID列表最多5个")
private List<String> schemeIds;
@Schema(description = "对比字段列表estimatedDuration / estimatedLossRatio / successRate / priority 等)")
private List<String> compareFields;
public List<String> getSchemeIds() {
return schemeIds;
}
public void setSchemeIds(List<String> schemeIds) {
this.schemeIds = schemeIds;
}
public List<String> getCompareFields() {
return compareFields;
}
public void setCompareFields(List<String> compareFields) {
this.compareFields = compareFields;
}
}

View File

@ -0,0 +1,53 @@
package com.example.demo.model.enums;
/**
* 事件来源类型枚举
* <p>
* 定义事件数据来源的传感器类型
* </p>
*/
public enum EventSourceType {
/** 雷达传感器 */
RADAR(1, "雷达"),
/** 光电传感器 */
OPTOELECTRONIC(2, "光电"),
/** 电子侦察 */
ELECTRONIC_RECON(3, "电子侦察"),
/** 通信情报 */
COMMUNICATION_INTEL(4, "通信情报");
private final int code;
private final String description;
EventSourceType(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
/**
* 根据来源码获取枚举实例
*
* @param code 来源码
* @return 对应的枚举实例
*/
public static EventSourceType fromCode(int code) {
for (EventSourceType type : values()) {
if (type.code == code) {
return type;
}
}
return null;
}
}

View File

@ -0,0 +1,56 @@
package com.example.demo.model.enums;
/**
* 事件处理状态枚举
* <p>
* 定义事件从接收到处理完成的完整生命周期状态
* </p>
*/
public enum EventStatus {
/** 待处理 - 事件已接收但尚未处理 */
PENDING(0, "待处理"),
/** 处理中 - 正在对事件进行分析评估 */
PROCESSING(1, "处理中"),
/** 已完成 - 事件已处理完成 */
COMPLETED(2, "已完成"),
/** 已忽略 - 事件经评估无需生成任务 */
IGNORED(3, "已忽略"),
/** 异常 - 事件处理过程中发生错误 */
ERROR(4, "异常");
private final int code;
private final String description;
EventStatus(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
/**
* 根据状态码获取枚举实例
*
* @param code 状态码
* @return 对应的枚举实例未找到时返回 null
*/
public static EventStatus fromCode(int code) {
for (EventStatus status : values()) {
if (status.code == code) {
return status;
}
}
return null;
}
}

View File

@ -0,0 +1,56 @@
package com.example.demo.model.enums;
/**
* 任务方案状态枚举
* <p>
* 定义任务方案从生成到执行完成的完整生命周期状态
* </p>
*/
public enum SchemeStatus {
/** 待分发 - 方案已生成但尚未下发 */
PENDING_DISPATCH(0, "待分发"),
/** 分发中 - 方案正在下发至执行节点 */
DISPATCHING(1, "分发中"),
/** 执行中 - 方案已下发,正在执行 */
EXECUTING(2, "执行中"),
/** 已完成 - 方案执行完毕 */
COMPLETED(3, "已完成"),
/** 已中止 - 方案执行被中止 */
ABORTED(4, "已中止");
private final int code;
private final String description;
SchemeStatus(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
/**
* 根据状态码获取枚举实例
*
* @param code 状态码
* @return 对应的枚举实例
*/
public static SchemeStatus fromCode(int code) {
for (SchemeStatus status : values()) {
if (status.code == code) {
return status;
}
}
return null;
}
}

View File

@ -0,0 +1,53 @@
package com.example.demo.model.enums;
/**
* 威胁等级枚举
* <p>
* 定义目标威胁程度的分级标准数值越高威胁越大
* </p>
*/
public enum ThreatLevel {
/** 低威胁 */
LOW(1, ""),
/** 中威胁 */
MEDIUM(2, ""),
/** 高威胁 */
HIGH(3, ""),
/** 极高威胁 */
CRITICAL(4, "极高");
private final int level;
private final String description;
ThreatLevel(int level, String description) {
this.level = level;
this.description = description;
}
public int getLevel() {
return level;
}
public String getDescription() {
return description;
}
/**
* 根据等级值获取枚举实例
*
* @param level 等级值
* @return 对应的枚举实例
*/
public static ThreatLevel fromLevel(int level) {
for (ThreatLevel tl : values()) {
if (tl.level == level) {
return tl;
}
}
return null;
}
}

View File

@ -0,0 +1,71 @@
package com.example.demo.repository;
import com.example.demo.model.Event;
import com.example.demo.model.enums.EventStatus;
import java.util.List;
import java.util.Optional;
/**
* 事件仓储接口
* <p>
* 定义事件数据的存储操作当前基于内存实现
* 后续可扩展为 PostgreSQL / 达梦DM8 数据库实现
* </p>
*/
public interface EventRepository {
/**
* 保存事件
*
* @param event 事件对象
* @return 保存后的事件
*/
Event save(Event event);
/**
* 根据ID查询事件
*
* @param eventId 事件ID
* @return 事件Optional
*/
Optional<Event> findById(String eventId);
/**
* 查询所有事件
*
* @return 事件列表
*/
List<Event> findAll();
/**
* 根据状态查询事件
*
* @param status 事件状态
* @return 事件列表
*/
List<Event> findByStatus(EventStatus status);
/**
* 更新事件状态
*
* @param eventId 事件ID
* @param status 新状态
* @return 更新后的事件
*/
Optional<Event> updateStatus(String eventId, EventStatus status);
/**
* 删除事件
*
* @param eventId 事件ID
*/
void deleteById(String eventId);
/**
* 统计事件总数
*
* @return 总数
*/
long count();
}

View File

@ -0,0 +1,81 @@
package com.example.demo.repository;
import com.example.demo.model.TaskScheme;
import com.example.demo.model.enums.SchemeStatus;
import java.util.List;
import java.util.Optional;
/**
* 任务方案仓储接口
* <p>
* 定义任务方案数据的存储操作当前基于内存实现
* 后续可扩展为 PostgreSQL / 达梦DM8 数据库实现
* </p>
*/
public interface SchemeRepository {
/**
* 保存任务方案
*
* @param scheme 任务方案
* @return 保存后的方案
*/
TaskScheme save(TaskScheme scheme);
/**
* 根据ID查询方案
*
* @param schemeId 方案ID
* @return 方案Optional
*/
Optional<TaskScheme> findById(String schemeId);
/**
* 查询所有任务方案
*
* @return 方案列表
*/
List<TaskScheme> findAll();
/**
* 根据状态查询方案
*
* @param status 方案状态
* @return 方案列表
*/
List<TaskScheme> findByStatus(SchemeStatus status);
/**
* 根据关联事件ID查询方案
*
* @param eventId 事件ID
* @return 方案列表
*/
List<TaskScheme> findByEventId(String eventId);
/**
* 更新方案状态
*
* @param schemeId 方案ID
* @param status 新状态
* @return 更新后的方案
*/
Optional<TaskScheme> updateStatus(String schemeId, SchemeStatus status);
/**
* 更新执行进度
*
* @param schemeId 方案ID
* @param progress 执行进度百分比
* @return 更新后的方案
*/
Optional<TaskScheme> updateProgress(String schemeId, int progress);
/**
* 删除方案
*
* @param schemeId 方案ID
*/
void deleteById(String schemeId);
}

View File

@ -0,0 +1,64 @@
package com.example.demo.repository;
import com.example.demo.model.TaskDraft;
import java.util.List;
import java.util.Optional;
/**
* 任务草案仓储接口
* <p>
* 定义任务草案数据的存储操作当前基于内存实现
* 后续可扩展为 PostgreSQL / 达梦DM8 数据库实现
* </p>
*/
public interface TaskDraftRepository {
/**
* 保存任务草案
*
* @param draft 任务草案
* @return 保存后的草案
*/
TaskDraft save(TaskDraft draft);
/**
* 根据ID查询任务草案
*
* @param draftId 草案ID
* @return 草案Optional
*/
Optional<TaskDraft> findById(String draftId);
/**
* 根据事件ID查询任务草案
*
* @param eventId 事件ID
* @return 草案列表
*/
List<TaskDraft> findByEventId(String eventId);
/**
* 查询所有任务草案
*
* @return 草案列表
*/
List<TaskDraft> findAll();
/**
* 查询所有发送失败的任务草案用于重试
*
* @return 发送失败的草案列表
*/
List<TaskDraft> findAllFailed();
/**
* 更新发送状态
*
* @param draftId 草案ID
* @param sendStatus 发送状态
* @param retryCount 重试次数
* @return 更新后的草案
*/
Optional<TaskDraft> updateSendStatus(String draftId, int sendStatus, int retryCount);
}

View File

@ -0,0 +1,54 @@
package com.example.demo.repository;
import com.example.demo.model.TaskTemplate;
import java.util.List;
import java.util.Optional;
/**
* 任务模板仓储接口
* <p>
* 定义任务模板数据的存储操作当前基于内存实现
* 后续可扩展为 PostgreSQL / 达梦DM8 数据库实现
* </p>
*/
public interface TaskTemplateRepository {
/**
* 保存模板
*
* @param template 任务模板
* @return 保存后的模板
*/
TaskTemplate save(TaskTemplate template);
/**
* 根据ID查询模板
*
* @param templateId 模板ID
* @return 模板Optional
*/
Optional<TaskTemplate> findById(String templateId);
/**
* 查询所有启用的模板
*
* @return 模板列表
*/
List<TaskTemplate> findAllActive();
/**
* 根据目标类型查询启用的模板
*
* @param targetType 目标类型
* @return 模板列表
*/
List<TaskTemplate> findByTargetType(int targetType);
/**
* 查询所有模板
*
* @return 模板列表
*/
List<TaskTemplate> findAll();
}

View File

@ -0,0 +1,112 @@
package com.example.demo.repository.impl;
import com.example.demo.model.Event;
import com.example.demo.model.enums.EventStatus;
import com.example.demo.repository.EventRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
/**
* 事件仓储内存实现
* <p>
* 使用 ConcurrentHashMap 模拟数据库存储应用启动时初始化示例数据
* 后续可替换为 MyBatis/JPA 等数据库实现
* </p>
*
* @requirement(name="事件存储与状态管理", id="SRS-EHTG-03")
* 将处理后的事件存入内存存储并维护其生命周期状态
*/
@Repository
public class InMemoryEventRepository implements EventRepository {
private final ConcurrentHashMap<String, Event> store = new ConcurrentHashMap<>();
private final AtomicLong idCounter = new AtomicLong(0);
public InMemoryEventRepository() {
initSampleData();
}
/**
* 初始化示例事件数据
*/
private void initSampleData() {
LocalDateTime now = LocalDateTime.now();
save(new Event("EVT-001", com.example.demo.model.enums.EventSourceType.RADAR,
now.minusMinutes(30), "{\"lng\": 116.397, \"lat\": 39.908}", 0.95,
EventStatus.PENDING, com.example.demo.model.enums.ThreatLevel.HIGH, "临机"));
save(new Event("EVT-002", com.example.demo.model.enums.EventSourceType.OPTOELECTRONIC,
now.minusMinutes(20), "{\"lng\": 121.473, \"lat\": 31.230}", 0.87,
EventStatus.PENDING, com.example.demo.model.enums.ThreatLevel.CRITICAL, "临机"));
save(new Event("EVT-003", com.example.demo.model.enums.EventSourceType.RADAR,
now.minusMinutes(15), "{\"lng\": 113.264, \"lat\": 23.129}", 0.72,
EventStatus.COMPLETED, com.example.demo.model.enums.ThreatLevel.MEDIUM, "规划"));
save(new Event("EVT-004", com.example.demo.model.enums.EventSourceType.ELECTRONIC_RECON,
now.minusMinutes(10), "{\"lng\": 114.057, \"lat\": 22.543}", 0.65,
EventStatus.PENDING, com.example.demo.model.enums.ThreatLevel.LOW, "规划"));
save(new Event("EVT-005", com.example.demo.model.enums.EventSourceType.COMMUNICATION_INTEL,
now.minusMinutes(5), "{\"lng\": 120.155, \"lat\": 30.274}", 0.91,
EventStatus.PROCESSING, com.example.demo.model.enums.ThreatLevel.HIGH, "临机"));
}
@Override
public Event save(Event event) {
if (event.getEventId() == null || event.getEventId().isEmpty()) {
String id = "EVT-" + String.format("%03d", idCounter.incrementAndGet());
event.setEventId(id);
}
event.setUpdateTime(LocalDateTime.now());
if (event.getCreateTime() == null) {
event.setCreateTime(LocalDateTime.now());
}
store.put(event.getEventId(), event);
return event;
}
@Override
public Optional<Event> findById(String eventId) {
return Optional.ofNullable(store.get(eventId));
}
@Override
public List<Event> findAll() {
return new ArrayList<>(store.values());
}
@Override
public List<Event> findByStatus(EventStatus status) {
return store.values().stream()
.filter(e -> e.getStatus() == status)
.collect(Collectors.toList());
}
@Override
public Optional<Event> updateStatus(String eventId, EventStatus status) {
return Optional.ofNullable(store.computeIfPresent(eventId, (id, event) -> {
event.setStatus(status);
event.setUpdateTime(LocalDateTime.now());
return event;
}));
}
@Override
public void deleteById(String eventId) {
store.remove(eventId);
}
@Override
public long count() {
return store.size();
}
}

View File

@ -0,0 +1,152 @@
package com.example.demo.repository.impl;
import com.example.demo.model.TaskScheme;
import com.example.demo.model.enums.SchemeStatus;
import com.example.demo.repository.SchemeRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
/**
* 任务方案仓储内存实现
* <p>
* 使用 ConcurrentHashMap 模拟数据库存储应用启动时初始化示例方案数据
* 后续可替换为 MyBatis/JPA 等数据库实现
* </p>
*
* @requirement(name="集中式/分布式方案列表展示", id="SRS-TMS-01")
* 以表格或卡片形式展示所有可用任务方案支持分页加载
*/
@Repository
public class InMemorySchemeRepository implements SchemeRepository {
private final ConcurrentHashMap<String, TaskScheme> store = new ConcurrentHashMap<>();
private final AtomicLong idCounter = new AtomicLong(0);
public InMemorySchemeRepository() {
initSampleData();
}
private void initSampleData() {
LocalDateTime now = LocalDateTime.now();
TaskScheme s1 = new TaskScheme("SCH-001", "联合打击方案-A", "集中式",
SchemeStatus.EXECUTING, 8, 120, 0.15, 0.92);
s1.setEventId("EVT-001");
s1.setDraftId("DRF-001");
s1.setDeploymentDetail("{\"air\":\"歼-20 4架\",\"ground\":\"火箭炮 2个连\",\"naval\":\"驱逐舰 1艘\"}");
s1.setRouteDetail("[{\"phase\":\"集结\",\"coord\":\"A(30.5,120.3)\"},{\"phase\":\"突击\",\"coord\":\"B(31.2,121.5)\"}]");
s1.setTimelineDetail("{\"T+0\":\"集结\",\"T+30min\":\"突击\",\"T+60min\":\"评估\"}");
s1.setAlgorithmTrace("路径规划采用A*算法优化约束满足率98.5%冲突消解2次");
s1.setExecutionProgress(45);
s1.setSubTaskStatus("[{\"name\":\"空中侦察\",\"progress\":80,\"status\":\"进行中\"},{\"name\":\"地面打击\",\"progress\":20,\"status\":\"进行中\"}]");
s1.setCreateTime(now.minusHours(2));
s1.setUpdateTime(now.minusMinutes(30));
store.put(s1.getSchemeId(), s1);
TaskScheme s2 = new TaskScheme("SCH-002", "分布式机动方案-B", "分布式",
SchemeStatus.PENDING_DISPATCH, 6, 90, 0.22, 0.85);
s2.setEventId("EVT-002");
s2.setDeploymentDetail("{\"air\":\"无人机 6架\",\"ground\":\"特种作战分队 1个\"}");
s2.setRouteDetail("[{\"phase\":\"渗透\",\"coord\":\"C(121.0,30.8)\"},{\"phase\":\"打击\",\"coord\":\"D(121.5,31.2)\"}]");
s2.setTimelineDetail("{\"T+0\":\"渗透\",\"T+45min\":\"打击\",\"T+80min\":\"撤离\"}");
s2.setAlgorithmTrace("分布式优化采用遗传算法种群规模500迭代100次");
s2.setExecutionProgress(0);
s2.setCreateTime(now.minusHours(1));
s2.setUpdateTime(now.minusMinutes(10));
store.put(s2.getSchemeId(), s2);
TaskScheme s3 = new TaskScheme("SCH-003", "区域防御方案-C", "集中式",
SchemeStatus.COMPLETED, 5, 180, 0.08, 0.96);
s3.setEventId("EVT-003");
s3.setDeploymentDetail("{\"air\":\"防空导弹 4个营\",\"ground\":\"雷达站 3座\"}");
s3.setRouteDetail("[]");
s3.setTimelineDetail("{\"T+0\":\"部署\",\"T+60min\":\"警戒\",\"T+180min\":\"撤防\"}");
s3.setAlgorithmTrace("区域防御覆盖优化最大覆盖半径300km重叠率<5%");
s3.setExecutionProgress(100);
s3.setSubTaskStatus("[{\"name\":\"防空部署\",\"progress\":100,\"status\":\"已完成\"}]");
s3.setCreateTime(now.minusDays(1));
s3.setUpdateTime(now.minusHours(5));
store.put(s3.getSchemeId(), s3);
TaskScheme s4 = new TaskScheme("SCH-004", "电子战压制方案-D", "分布式",
SchemeStatus.ABORTED, 7, 60, 0.18, 0.78);
s4.setEventId("EVT-004");
s4.setDeploymentDetail("{\"electronic\":\"电子战飞机 2架\",\"ground\":\"干扰站 2个\"}");
s4.setRouteDetail("[{\"phase\":\"抵近\",\"coord\":\"E(119.5,29.3)\"}]");
s4.setTimelineDetail("{\"T+0\":\"抵近\",\"T+30min\":\"压制\"}");
s4.setAlgorithmTrace("电子频谱分配算法冲突率0%,但目标移动导致方案中止");
s4.setExecutionProgress(30);
s4.setSubTaskStatus("[{\"name\":\"电子侦察\",\"progress\":100,\"status\":\"已完成\"},{\"name\":\"干扰压制\",\"progress\":0,\"status\":\"已中止\"}]");
s4.setCreateTime(now.minusHours(6));
s4.setUpdateTime(now.minusHours(3));
store.put(s4.getSchemeId(), s4);
}
@Override
public TaskScheme save(TaskScheme scheme) {
if (scheme.getSchemeId() == null || scheme.getSchemeId().isEmpty()) {
String id = "SCH-" + String.format("%03d", idCounter.incrementAndGet());
scheme.setSchemeId(id);
}
scheme.setUpdateTime(LocalDateTime.now());
if (scheme.getCreateTime() == null) {
scheme.setCreateTime(LocalDateTime.now());
}
store.put(scheme.getSchemeId(), scheme);
return scheme;
}
@Override
public Optional<TaskScheme> findById(String schemeId) {
return Optional.ofNullable(store.get(schemeId));
}
@Override
public List<TaskScheme> findAll() {
return new ArrayList<>(store.values());
}
@Override
public List<TaskScheme> findByStatus(SchemeStatus status) {
return store.values().stream()
.filter(s -> s.getStatus() == status)
.collect(Collectors.toList());
}
@Override
public List<TaskScheme> findByEventId(String eventId) {
return store.values().stream()
.filter(s -> eventId.equals(s.getEventId()))
.collect(Collectors.toList());
}
@Override
public Optional<TaskScheme> updateStatus(String schemeId, SchemeStatus status) {
return Optional.ofNullable(store.computeIfPresent(schemeId, (id, scheme) -> {
scheme.setStatus(status);
scheme.setUpdateTime(LocalDateTime.now());
return scheme;
}));
}
@Override
public Optional<TaskScheme> updateProgress(String schemeId, int progress) {
return Optional.ofNullable(store.computeIfPresent(schemeId, (id, scheme) -> {
scheme.setExecutionProgress(progress);
scheme.setUpdateTime(LocalDateTime.now());
return scheme;
}));
}
@Override
public void deleteById(String schemeId) {
store.remove(schemeId);
}
}

View File

@ -0,0 +1,77 @@
package com.example.demo.repository.impl;
import com.example.demo.model.TaskDraft;
import com.example.demo.repository.TaskDraftRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
/**
* 任务草案仓储内存实现
* <p>
* 使用 ConcurrentHashMap 模拟数据库存储
* 后续可替换为 MyBatis/JPA 等数据库实现
* </p>
*
* @requirement(name="任务草案发送与重试机制", id="SRS-EHTG-07")
* 向下游任务规划引擎发送请求失败时自动加入本地重试队列
*/
@Repository
public class InMemoryTaskDraftRepository implements TaskDraftRepository {
private final ConcurrentHashMap<String, TaskDraft> store = new ConcurrentHashMap<>();
private final AtomicLong idCounter = new AtomicLong(0);
@Override
public TaskDraft save(TaskDraft draft) {
if (draft.getDraftId() == null || draft.getDraftId().isEmpty()) {
String id = "DRF-" + String.format("%03d", idCounter.incrementAndGet());
draft.setDraftId(id);
}
if (draft.getCreateTime() == null) {
draft.setCreateTime(LocalDateTime.now());
}
store.put(draft.getDraftId(), draft);
return draft;
}
@Override
public Optional<TaskDraft> findById(String draftId) {
return Optional.ofNullable(store.get(draftId));
}
@Override
public List<TaskDraft> findByEventId(String eventId) {
return store.values().stream()
.filter(d -> eventId.equals(d.getEventId()))
.collect(Collectors.toList());
}
@Override
public List<TaskDraft> findAll() {
return new ArrayList<>(store.values());
}
@Override
public List<TaskDraft> findAllFailed() {
return store.values().stream()
.filter(d -> d.getSendStatus() == 2)
.collect(Collectors.toList());
}
@Override
public Optional<TaskDraft> updateSendStatus(String draftId, int sendStatus, int retryCount) {
return Optional.ofNullable(store.computeIfPresent(draftId, (id, draft) -> {
draft.setSendStatus(sendStatus);
draft.setRetryCount(retryCount);
draft.setLastSendTime(LocalDateTime.now());
return draft;
}));
}
}

View File

@ -0,0 +1,79 @@
package com.example.demo.repository.impl;
import com.example.demo.model.TaskTemplate;
import com.example.demo.repository.TaskTemplateRepository;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* 任务模板仓储内存实现
* <p>
* 使用 ConcurrentHashMap 模拟数据库存储应用启动时初始化示例模板数据
* 后续可替换为 MyBatis/JPA 等数据库实现
* </p>
*
* @requirement(name="任务模板匹配与生成", id="SRS-EHTG-06")
* 结合知识库中的任务模板自动生成符合标准的任务草案
*/
@Repository
public class InMemoryTaskTemplateRepository implements TaskTemplateRepository {
private final ConcurrentHashMap<String, TaskTemplate> store = new ConcurrentHashMap<>();
public InMemoryTaskTemplateRepository() {
initSampleData();
}
private void initSampleData() {
save(new TaskTemplate("TPL-001", 1,
"<task><type>侦察打击</type><phase>侦察</phase><action>高空侦察</action><target>固定目标</target></task>",
"V1.0", true, "高空侦察打击模板", "适用于固定目标的侦察与精确打击"));
save(new TaskTemplate("TPL-002", 2,
"<task><type>电子干扰</type><phase>压制</phase><action>雷达干扰</action><target>移动目标</target></task>",
"V1.0", true, "电子干扰压制模板", "适用于移动目标的电子干扰与压制"));
save(new TaskTemplate("TPL-003", 3,
"<task><type>联合打击</type><phase>协同</phase><action>多兵种协同打击</action><target>高价值目标</target></task>",
"V2.0", true, "多兵种联合打击模板", "适用于高价值目标的联合打击行动"));
save(new TaskTemplate("TPL-004", 1,
"<task><type>侦察</type><phase>监视</phase><action>低空监视</action><target>区域监控</target></task>",
"V1.5", false, "低空区域监控模板", "已停用,适用于区域监视"));
}
@Override
public TaskTemplate save(TaskTemplate template) {
store.put(template.getTemplateId(), template);
return template;
}
@Override
public Optional<TaskTemplate> findById(String templateId) {
return Optional.ofNullable(store.get(templateId));
}
@Override
public List<TaskTemplate> findAllActive() {
return store.values().stream()
.filter(TaskTemplate::isActive)
.collect(Collectors.toList());
}
@Override
public List<TaskTemplate> findByTargetType(int targetType) {
return store.values().stream()
.filter(t -> t.getTargetType() == targetType && t.isActive())
.collect(Collectors.toList());
}
@Override
public List<TaskTemplate> findAll() {
return new ArrayList<>(store.values());
}
}

View File

@ -0,0 +1,204 @@
package com.example.demo.service;
import com.example.demo.model.Event;
import com.example.demo.model.dto.EventDTO;
import com.example.demo.model.dto.EventQueryDTO;
import com.example.demo.model.enums.EventStatus;
import com.example.demo.repository.EventRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* 事件处理服务
* <p>
* 实现事件的接收清洗标准化存储与状态管理等核心业务逻辑
* </p>
*
* @requirement(name="事件接收与解析", id="SRS-EHTG-01")
* 监听上游消息队列接收原始事件数据包并进行格式校验
*
* @requirement(name="数据清洗与标准化", id="SRS-EHTG-02")
* 对原始事件进行去重过滤字段补全和结构化转换
*
* @requirement(name="事件存储与状态管理", id="SRS-EHTG-03")
* 将处理后的事件存入数据库并维护其生命周期状态
*
* @requirement(name="高价值目标评估", id="SRS-EHTG-05")
* 基于威胁等级置信度等指标计算目标价值判定是否触发任务生成
*/
@Service
public class EventService {
private static final Logger log = LoggerFactory.getLogger(EventService.class);
private final EventRepository eventRepository;
public EventService(EventRepository eventRepository) {
this.eventRepository = eventRepository;
}
/**
* 接收并处理原始事件
* <p>
* 执行数据清洗与标准化流程
* 1. 格式校验
* 2. 字段补全
* 3. 去重检查
* 4. 结构化转换并存储
* </p>
*
* @param rawEvent 原始事件数据
* @return 处理后的事件
*/
public Event receiveEvent(Event rawEvent) {
log.info("接收到原始事件,来源: {}, 时间: {}", rawEvent.getSourceType(), rawEvent.getOccurTime());
// 格式校验置信度必须在0~1之间
if (rawEvent.getConfidence() < 0 || rawEvent.getConfidence() > 1) {
log.warn("事件置信度异常: {}, 已自动修正", rawEvent.getConfidence());
rawEvent.setConfidence(Math.max(0, Math.min(1, rawEvent.getConfidence())));
}
// 字段补全如果状态为空默认设置为待处理
if (rawEvent.getStatus() == null) {
rawEvent.setStatus(EventStatus.PENDING);
}
// 去重检查按事件ID
if (rawEvent.getEventId() != null && !rawEvent.getEventId().isEmpty()) {
Optional<Event> existing = eventRepository.findById(rawEvent.getEventId());
if (existing.isPresent()) {
log.info("事件 {} 已存在,跳过重复接收", rawEvent.getEventId());
return existing.get();
}
}
// 结构化转换并存储
Event savedEvent = eventRepository.save(rawEvent);
log.info("事件 {} 已清洗并存储", savedEvent.getEventId());
return savedEvent;
}
/**
* 评估目标价值
* <p>
* 基于威胁等级和置信度计算目标价值评分
* 评分公式威胁等级值 × 置信度 × 100
* 评分 > 200 视为高价值目标
* </p>
*
* @param event 事件
* @return 目标价值评分0~400
*/
public double evaluateTargetValue(Event event) {
double threatScore = event.getThreatLevel() != null ? event.getThreatLevel().getLevel() : 1;
double confidence = event.getConfidence();
double score = threatScore * confidence * 100;
log.info("事件 {} 目标价值评估: 威胁={}, 置信度={}, 评分={}",
event.getEventId(), threatScore, confidence, score);
return score;
}
/**
* 判断是否为高价值目标评分 > 200
*
* @param score 目标价值评分
* @return true 如果是高价值目标
*/
public boolean isHighValueTarget(double score) {
return score > 200;
}
/**
* 查询事件列表支持排序和过滤
*
* @param query 查询参数
* @return 事件列表
*/
public List<Event> queryEvents(EventQueryDTO query) {
List<Event> events = new ArrayList<>(eventRepository.findAll());
// 状态过滤
if (query.getStatusFilter() != null && !query.getStatusFilter().isEmpty()) {
events = events.stream()
.filter(e -> e.getStatus() != null &&
e.getStatus().getDescription().contains(query.getStatusFilter()))
.collect(Collectors.toList());
}
// 威胁等级过滤
if (query.getThreatLevel() != null) {
events = events.stream()
.filter(e -> e.getThreatLevel() == query.getThreatLevel())
.collect(Collectors.toList());
}
// 排序
String sortField = query.getSortField();
String sortDir = query.getSortDirection();
if (sortField != null && !sortField.isEmpty()) {
Comparator<Event> comparator = getComparator(sortField);
if (comparator != null) {
if ("desc".equalsIgnoreCase(sortDir)) {
events.sort(comparator.reversed());
} else {
events.sort(comparator);
}
}
}
// 分页
int page = Math.max(0, query.getPage());
int size = Math.max(1, Math.min(100, query.getSize() > 0 ? query.getSize() : 20));
int fromIndex = page * size;
if (fromIndex >= events.size()) {
return new ArrayList<>();
}
int toIndex = Math.min(fromIndex + size, events.size());
return events.subList(fromIndex, toIndex);
}
/**
* 获取排序比较器
*/
private Comparator<Event> getComparator(String sortField) {
return switch (sortField) {
case "createTime" -> Comparator.comparing(Event::getCreateTime, Comparator.nullsLast(Comparator.naturalOrder()));
case "occurTime" -> Comparator.comparing(Event::getOccurTime, Comparator.nullsLast(Comparator.naturalOrder()));
case "threatLevel" -> Comparator.comparing(e -> e.getThreatLevel() != null ? e.getThreatLevel().getLevel() : 0);
case "confidence" -> Comparator.comparing(Event::getConfidence);
default -> null;
};
}
/**
* 根据ID查询事件
*
* @param eventId 事件ID
* @return 事件
*/
public Optional<Event> getEventById(String eventId) {
return eventRepository.findById(eventId);
}
/**
* 更新事件状态
*
* @param eventId 事件ID
* @param status 新状态
* @return 更新后的事件
*/
public Optional<Event> updateEventStatus(String eventId, EventStatus status) {
log.info("更新事件 {} 状态为 {}", eventId, status);
return eventRepository.updateStatus(eventId, status);
}
}

View File

@ -0,0 +1,296 @@
package com.example.demo.service;
import com.example.demo.model.TaskScheme;
import com.example.demo.model.dto.SchemeCompareDTO;
import com.example.demo.model.enums.SchemeStatus;
import com.example.demo.repository.SchemeRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/**
* 任务方案管理服务
* <p>
* 实现集中式/分布式任务方案的统一管理对比重构及执行监控能力
* </p>
*
* @requirement(name="集中式/分布式方案列表展示", id="SRS-TMS-01")
* 以表格或卡片形式展示所有可用任务方案支持分页加载
*
* @requirement(name="自定义排序功能", id="SRS-TMS-02")
* 按生成时间优先级成功率等字段升序/降序排列
*
* @requirement(name="方案详情查看", id="SRS-TMS-03")
* 展示兵力部署行动路线时间节点等详细信息
*
* @requirement(name="多方案对比分析", id="SRS-TMS-04")
* 支持最多5个方案的关键指标并列比较
*
* @requirement(name="方案重构操作", id="SRS-TMS-06")
* 基于新约束条件重新生成或调整现有方案
*
* @requirement(name="方案分发驱动", id="SRS-TMS-08")
* 将选定方案解析为指令集下发至指定执行节点
*
* @requirement(name="执行状态监控", id="SRS-TMS-10")
* 实时聚合子任务进度展示整体完成率与当前状态
*/
@Service
public class SchemeService {
private static final Logger log = LoggerFactory.getLogger(SchemeService.class);
private final SchemeRepository schemeRepository;
public SchemeService(SchemeRepository schemeRepository) {
this.schemeRepository = schemeRepository;
}
/**
* 查询任务方案列表支持排序和分页
*
* @param sortField 排序字段createTime / priority / successRate / estimatedDuration / estimatedLossRatio
* @param sortDirection 排序方向asc / desc
* @param page 页码
* @param size 每页条数
* @return 方案列表
*/
public List<TaskScheme> listSchemes(String sortField, String sortDirection, int page, int size) {
List<TaskScheme> schemes = new ArrayList<>(schemeRepository.findAll());
// 排序
if (sortField != null && !sortField.isEmpty()) {
Comparator<TaskScheme> comparator = getComparator(sortField);
if (comparator != null) {
if ("desc".equalsIgnoreCase(sortDirection)) {
schemes.sort(comparator.reversed());
} else {
schemes.sort(comparator);
}
}
}
// 分页
int fromIndex = Math.max(0, page * size);
if (fromIndex >= schemes.size()) {
return new ArrayList<>();
}
int toIndex = Math.min(fromIndex + size, schemes.size());
return schemes.subList(fromIndex, toIndex);
}
/**
* 获取排序比较器
*/
private Comparator<TaskScheme> getComparator(String sortField) {
return switch (sortField) {
case "createTime" -> Comparator.comparing(TaskScheme::getCreateTime, Comparator.nullsLast(Comparator.naturalOrder()));
case "priority" -> Comparator.comparingInt(TaskScheme::getPriority);
case "successRate" -> Comparator.comparingDouble(TaskScheme::getSuccessRate);
case "estimatedDuration" -> Comparator.comparingInt(TaskScheme::getEstimatedDuration);
case "estimatedLossRatio" -> Comparator.comparingDouble(TaskScheme::getEstimatedLossRatio);
default -> Comparator.comparing(TaskScheme::getCreateTime, Comparator.nullsLast(Comparator.naturalOrder()));
};
}
/**
* 查询方案详情
*
* @param schemeId 方案ID
* @return 方案
*/
public Optional<TaskScheme> getSchemeDetail(String schemeId) {
return schemeRepository.findById(schemeId);
}
/**
* 多方案对比分析
* <p>
* 最多支持5个方案的关键指标并列比较
* </p>
*
* @param compareDTO 对比参数
* @return 对比结果Map
*/
public Map<String, Object> compareSchemes(SchemeCompareDTO compareDTO) {
List<String> schemeIds = compareDTO.getSchemeIds();
if (schemeIds == null || schemeIds.isEmpty()) {
throw new IllegalArgumentException("至少需要一个方案进行对比");
}
if (schemeIds.size() > 5) {
throw new IllegalArgumentException("最多支持5个方案对比");
}
List<String> compareFields = compareDTO.getCompareFields();
if (compareFields == null || compareFields.isEmpty()) {
compareFields = Arrays.asList("estimatedDuration", "estimatedLossRatio", "successRate", "priority");
}
Map<String, Object> result = new LinkedHashMap<>();
result.put("compareFields", compareFields);
List<Map<String, Object>> schemeComparisons = new ArrayList<>();
for (String schemeId : schemeIds) {
Optional<TaskScheme> schemeOpt = schemeRepository.findById(schemeId);
if (schemeOpt.isPresent()) {
TaskScheme scheme = schemeOpt.get();
Map<String, Object> schemeData = new LinkedHashMap<>();
schemeData.put("schemeId", scheme.getSchemeId());
schemeData.put("schemeName", scheme.getSchemeName());
schemeData.put("schemeType", scheme.getSchemeType());
schemeData.put("status", scheme.getStatus());
for (String field : compareFields) {
Object value = getFieldValue(scheme, field);
schemeData.put(field, value);
}
schemeComparisons.add(schemeData);
}
}
result.put("schemes", schemeComparisons);
return result;
}
/**
* 获取方案字段值
*/
private Object getFieldValue(TaskScheme scheme, String field) {
return switch (field) {
case "estimatedDuration" -> scheme.getEstimatedDuration();
case "estimatedLossRatio" -> scheme.getEstimatedLossRatio();
case "successRate" -> scheme.getSuccessRate();
case "priority" -> scheme.getPriority();
case "executionProgress" -> scheme.getExecutionProgress();
case "version" -> scheme.getVersion();
default -> null;
};
}
/**
* 方案重构
* <p>
* 基于新约束条件重新生成方案保留与旧版本的关联
* </p>
*
* @param schemeId 原方案ID
* @param newConstraints 新约束条件JSON格式
* @return 重构后的新方案
*/
public TaskScheme reconstructScheme(String schemeId, String newConstraints) {
TaskScheme original = schemeRepository.findById(schemeId)
.orElseThrow(() -> new IllegalArgumentException("方案不存在: " + schemeId));
log.info("开始重构方案 {},新约束: {}", schemeId, newConstraints);
// 创建新方案基于原方案调整
TaskScheme newScheme = new TaskScheme();
newScheme.setSchemeName(original.getSchemeName() + " (重构版)");
newScheme.setSchemeType(original.getSchemeType());
newScheme.setEventId(original.getEventId());
newScheme.setDraftId(original.getDraftId());
newScheme.setStatus(SchemeStatus.PENDING_DISPATCH);
newScheme.setPriority(original.getPriority());
newScheme.setEstimatedDuration(original.getEstimatedDuration());
newScheme.setEstimatedLossRatio(original.getEstimatedLossRatio());
newScheme.setSuccessRate(original.getSuccessRate());
newScheme.setDeploymentDetail(original.getDeploymentDetail());
newScheme.setRouteDetail(original.getRouteDetail());
newScheme.setTimelineDetail(original.getTimelineDetail());
newScheme.setAlgorithmTrace("基于原方案 " + schemeId + " 重构,新约束: " + newConstraints);
newScheme.setParentSchemeId(schemeId);
newScheme.setVersion(original.getVersion() + 1);
newScheme.setExecutionProgress(0);
newScheme.setCreateTime(LocalDateTime.now());
newScheme.setUpdateTime(LocalDateTime.now());
TaskScheme saved = schemeRepository.save(newScheme);
log.info("方案重构完成新方案ID: {}", saved.getSchemeId());
return saved;
}
/**
* 方案分发
* <p>
* 将选定方案解析为指令集并下发至指定执行节点
* </p>
*
* @param schemeId 方案ID
* @param targetNode 目标执行节点
* @return 分发结果
*/
public Map<String, Object> dispatchScheme(String schemeId, String targetNode) {
TaskScheme scheme = schemeRepository.findById(schemeId)
.orElseThrow(() -> new IllegalArgumentException("方案不存在: " + schemeId));
log.info("分发方案 {} 至执行节点: {}", schemeId, targetNode);
// 更新方案状态为"分发中"
schemeRepository.updateStatus(schemeId, SchemeStatus.DISPATCHING);
// 构建分发指令集
Map<String, Object> dispatchResult = new LinkedHashMap<>();
dispatchResult.put("schemeId", schemeId);
dispatchResult.put("schemeName", scheme.getSchemeName());
dispatchResult.put("targetNode", targetNode);
dispatchResult.put("dispatchTime", LocalDateTime.now().toString());
dispatchResult.put("status", "已下发");
dispatchResult.put("instructions", buildInstructions(scheme));
// 模拟下发成功更新状态为"执行中"
schemeRepository.updateStatus(schemeId, SchemeStatus.EXECUTING);
log.info("方案 {} 已成功分发给节点 {}", schemeId, targetNode);
return dispatchResult;
}
/**
* 构建指令集
*/
private List<Map<String, String>> buildInstructions(TaskScheme scheme) {
List<Map<String, String>> instructions = new ArrayList<>();
Map<String, String> cmd1 = new LinkedHashMap<>();
cmd1.put("command", "DEPLOY");
cmd1.put("target", scheme.getDeploymentDetail() != null ? "兵力部署" : "未知");
cmd1.put("detail", scheme.getDeploymentDetail() != null ? scheme.getDeploymentDetail() : "{}");
instructions.add(cmd1);
Map<String, String> cmd2 = new LinkedHashMap<>();
cmd2.put("command", "MOVE");
cmd2.put("target", "行动路线");
cmd2.put("detail", scheme.getRouteDetail() != null ? scheme.getRouteDetail() : "[]");
instructions.add(cmd2);
Map<String, String> cmd3 = new LinkedHashMap<>();
cmd3.put("command", "TIMELINE");
cmd3.put("target", "时间节点");
cmd3.put("detail", scheme.getTimelineDetail() != null ? scheme.getTimelineDetail() : "{}");
instructions.add(cmd3);
return instructions;
}
/**
* 查询方案执行状态
*
* @param schemeId 方案ID
* @return 执行状态信息
*/
public Map<String, Object> getExecutionStatus(String schemeId) {
TaskScheme scheme = schemeRepository.findById(schemeId)
.orElseThrow(() -> new IllegalArgumentException("方案不存在: " + schemeId));
Map<String, Object> status = new LinkedHashMap<>();
status.put("schemeId", scheme.getSchemeId());
status.put("schemeName", scheme.getSchemeName());
status.put("status", scheme.getStatus());
status.put("executionProgress", scheme.getExecutionProgress());
status.put("subTaskStatus", scheme.getSubTaskStatus());
status.put("updateTime", scheme.getUpdateTime());
return status;
}
}

View File

@ -0,0 +1,240 @@
package com.example.demo.service;
import com.example.demo.model.Event;
import com.example.demo.model.TaskDraft;
import com.example.demo.model.TaskTemplate;
import com.example.demo.repository.TaskDraftRepository;
import com.example.demo.repository.TaskTemplateRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
/**
* 任务生成服务
* <p>
* 实现高价值目标评估后的任务模板匹配与任务草案生成逻辑
* 以及任务草案发送与重试机制
* </p>
*
* @requirement(name="任务模板匹配与生成", id="SRS-EHTG-06")
* 结合知识库中的任务模板自动生成符合标准的任务草案
*
* @requirement(name="任务草案发送与重试机制", id="SRS-EHTG-07")
* 向下游任务规划引擎发送请求失败时自动加入本地重试队列
*/
@Service
public class TaskGenerationService {
private static final Logger log = LoggerFactory.getLogger(TaskGenerationService.class);
private final TaskTemplateRepository templateRepository;
private final TaskDraftRepository draftRepository;
private final EventService eventService;
public TaskGenerationService(TaskTemplateRepository templateRepository,
TaskDraftRepository draftRepository,
EventService eventService) {
this.templateRepository = templateRepository;
this.draftRepository = draftRepository;
this.eventService = eventService;
}
/**
* 基于事件生成任务草案
* <p>
* 执行流程
* 1. 评估目标价值
* 2. 若为高价值目标匹配任务模板
* 3. 填充模板参数生成任务草案
* 4. 保存草案并返回
* </p>
*
* @param eventId 事件ID
* @return 生成的任务草案
* @throws IllegalArgumentException 如果事件不存在或不是高价值目标
*/
public TaskDraft generateTaskDraft(String eventId) {
Event event = eventService.getEventById(eventId)
.orElseThrow(() -> new IllegalArgumentException("事件不存在: " + eventId));
// 评估目标价值
double score = eventService.evaluateTargetValue(event);
if (!eventService.isHighValueTarget(score)) {
throw new IllegalArgumentException("事件 " + eventId + " 目标价值评分 " + score + ",未达到高价值目标阈值");
}
// 匹配任务模板按目标类型匹配
int targetType = event.getSourceType() != null ? event.getSourceType().getCode() : 1;
List<TaskTemplate> templates = templateRepository.findByTargetType(targetType);
if (templates.isEmpty()) {
// 如果没有精确匹配的模板使用所有启用的模板中的第一个
templates = templateRepository.findAllActive();
}
if (templates.isEmpty()) {
throw new IllegalStateException("没有可用的任务模板");
}
// 选择第一个匹配的模板
TaskTemplate template = templates.get(0);
log.info("为事件 {} 匹配到模板: {} (版本 {})", eventId, template.getTemplateName(), template.getVersion());
// 生成任务草案内容
String draftContent = generateDraftContent(event, template, score);
// 创建任务草案
TaskDraft draft = new TaskDraft();
draft.setDraftId("DRF-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase());
draft.setEventId(eventId);
draft.setTemplateId(template.getTemplateId());
draft.setTitle(template.getTemplateName() + " - " + event.getEventId());
draft.setContent(draftContent);
draft.setTargetValueScore(score);
draft.setSendStatus(0); // 未发送
draft.setRetryCount(0);
draft.setCreateTime(LocalDateTime.now());
TaskDraft savedDraft = draftRepository.save(draft);
log.info("任务草案 {} 已生成", savedDraft.getDraftId());
// 更新事件状态为处理中
eventService.updateEventStatus(eventId, com.example.demo.model.enums.EventStatus.PROCESSING);
return savedDraft;
}
/**
* 生成任务草案内容
* <p>
* 根据事件信息和模板生成结构化的任务草案内容JSON格式
* </p>
*/
private String generateDraftContent(Event event, TaskTemplate template, double score) {
return String.format("{" +
"\"eventId\":\"%s\"," +
"\"templateId\":\"%s\"," +
"\"targetValueScore\":%.2f," +
"\"threatLevel\":\"%s\"," +
"\"confidence\":%.2f," +
"\"location\":%s," +
"\"templateContent\":%s" +
"}",
event.getEventId(),
template.getTemplateId(),
score,
event.getThreatLevel() != null ? event.getThreatLevel().name() : "UNKNOWN",
event.getConfidence(),
event.getLocation() != null ? event.getLocation() : "\"\"",
template.getContentXml() != null ? "\"" + template.getContentXml().replace("\"", "\\\"") + "\"" : "\"\"");
}
/**
* 发送任务草案到下游任务规划引擎
* <p>
* 模拟发送过程随机成功/失败失败时记录重试
* 后续对接真实下游引擎时替换此方法
* </p>
*
* @param draftId 草案ID
* @return 发送是否成功
*/
public boolean sendTaskDraft(String draftId) {
Optional<TaskDraft> draftOpt = draftRepository.findById(draftId);
if (draftOpt.isEmpty()) {
log.warn("任务草案 {} 不存在,无法发送", draftId);
return false;
}
TaskDraft draft = draftOpt.get();
log.info("发送任务草案 {} 到下游任务规划引擎...", draftId);
try {
// 模拟发送过程当前阶段返回发送成功
boolean sendSuccess = simulateSendToEngine(draft);
if (sendSuccess) {
draftRepository.updateSendStatus(draftId, 1, draft.getRetryCount());
log.info("任务草案 {} 发送成功", draftId);
// 更新事件状态为已完成
eventService.updateEventStatus(draft.getEventId(), com.example.demo.model.enums.EventStatus.COMPLETED);
return true;
} else {
int newRetry = draft.getRetryCount() + 1;
draftRepository.updateSendStatus(draftId, 2, newRetry);
log.warn("任务草案 {} 发送失败,重试次数: {}", draftId, newRetry);
return false;
}
} catch (Exception e) {
int newRetry = draft.getRetryCount() + 1;
draftRepository.updateSendStatus(draftId, 2, newRetry);
log.error("任务草案 {} 发送异常: {}", draftId, e.getMessage());
return false;
}
}
/**
* 模拟向下游引擎发送消息
* <p>
* 当前实现模拟成功后续对接真实引擎时替换
* </p>
*/
private boolean simulateSendToEngine(TaskDraft draft) {
// 模拟前两次重试随机失败之后成功
if (draft.getRetryCount() < 2) {
return true;
}
return true;
}
/**
* 重试发送失败的任务草案
*
* @param draftId 草案ID
* @return 重试结果
*/
public boolean retrySendDraft(String draftId) {
Optional<TaskDraft> draftOpt = draftRepository.findById(draftId);
if (draftOpt.isEmpty()) {
return false;
}
TaskDraft draft = draftOpt.get();
if (draft.getSendStatus() != 2) {
log.info("任务草案 {} 当前状态不是发送失败,无需重试", draftId);
return false;
}
return sendTaskDraft(draftId);
}
/**
* 查询所有发送失败的任务草案
*
* @return 失败的草案列表
*/
public List<TaskDraft> getFailedDrafts() {
return draftRepository.findAllFailed();
}
/**
* 查询任务草案列表
*
* @return 所有草案
*/
public List<TaskDraft> getAllDrafts() {
return draftRepository.findAll();
}
/**
* 根据ID查询任务草案
*
* @param draftId 草案ID
* @return 草案
*/
public Optional<TaskDraft> getDraftById(String draftId) {
return draftRepository.findById(draftId);
}
}

View File

@ -0,0 +1,44 @@
server:
port: 8080
spring:
application:
name: battlefield-mission-system
# 当前阶段使用内存存储,未配置数据库
# 后续扩展:取消注释下方配置并引入 spring-boot-starter-data-jpa 和 postgresql 依赖
# datasource:
# url: jdbc:postgresql://localhost:5432/battlefield
# username: battlefield_user
# password: ${DB_PASSWORD}
# driver-class-name: org.postgresql.Driver
# jpa:
# hibernate:
# ddl-auto: update
# show-sql: true
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Shanghai
serialization:
write-dates-as-timestamps: false
# Knife4j 配置
knife4j:
enable: true
setting:
language: zh-CN
enable-swagger-models: true
enable-document-manage: true
enable-reload-cache: false
enable-footer: false
enable-footer-custom: true
footer-custom-content: 战场态势与任务规划系统 - 保密
# 日志配置
logging:
level:
com.example.demo: INFO
org.springframework: WARN
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

View File

@ -0,0 +1,118 @@
package com.example.demo;
import com.example.demo.model.Event;
import com.example.demo.model.enums.EventSourceType;
import com.example.demo.model.enums.EventStatus;
import com.example.demo.model.enums.ThreatLevel;
import com.example.demo.service.EventService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
/**
* 事件服务单元测试
* <p>
* 测试事件接收清洗目标价值评估等核心业务逻辑
* </p>
*
* @requirement(name="事件接收与解析", id="SRS-EHTG-01")
* @requirement(name="数据清洗与标准化", id="SRS-EHTG-02")
* @requirement(name="高价值目标评估", id="SRS-EHTG-05")
*/
@SpringBootTest
class EventServiceTest {
@Autowired
private EventService eventService;
@Test
@DisplayName("测试接收事件 - 正常流程")
void testReceiveEvent() {
Event event = new Event();
event.setSourceType(EventSourceType.RADAR);
event.setOccurTime(LocalDateTime.now());
event.setLocation("{\"lng\": 116.397, \"lat\": 39.908}");
event.setConfidence(0.95);
event.setThreatLevel(ThreatLevel.HIGH);
event.setEventType("临机");
Event saved = eventService.receiveEvent(event);
assertNotNull(saved);
assertNotNull(saved.getEventId());
assertEquals(EventStatus.PENDING, saved.getStatus());
assertNotNull(saved.getCreateTime());
}
@Test
@DisplayName("测试接收事件 - 置信度修正")
void testReceiveEventWithInvalidConfidence() {
Event event = new Event();
event.setSourceType(EventSourceType.OPTOELECTRONIC);
event.setOccurTime(LocalDateTime.now());
event.setLocation("{\"lng\": 121.473, \"lat\": 31.230}");
event.setConfidence(2.5); // 无效置信度
event.setThreatLevel(ThreatLevel.CRITICAL);
event.setEventType("临机");
Event saved = eventService.receiveEvent(event);
assertEquals(1.0, saved.getConfidence(), 0.001);
}
@Test
@DisplayName("测试目标价值评估 - 高价值目标")
void testEvaluateHighValueTarget() {
Event event = new Event();
event.setEventId("EVT-TEST-001");
event.setThreatLevel(ThreatLevel.CRITICAL); // 等级4
event.setConfidence(0.95);
double score = eventService.evaluateTargetValue(event);
// 4 * 0.95 * 100 = 380
assertEquals(380.0, score, 0.01);
assertTrue(eventService.isHighValueTarget(score));
}
@Test
@DisplayName("测试目标价值评估 - 低价值目标")
void testEvaluateLowValueTarget() {
Event event = new Event();
event.setEventId("EVT-TEST-002");
event.setThreatLevel(ThreatLevel.LOW); // 等级1
event.setConfidence(0.5);
double score = eventService.evaluateTargetValue(event);
// 1 * 0.5 * 100 = 50
assertEquals(50.0, score, 0.01);
assertFalse(eventService.isHighValueTarget(score));
}
@Test
@DisplayName("测试查询事件 - 按ID查询")
void testGetEventById() {
Optional<Event> event = eventService.getEventById("EVT-001");
assertTrue(event.isPresent());
assertEquals("EVT-001", event.get().getEventId());
}
@Test
@DisplayName("测试查询事件 - 不存在的ID")
void testGetEventByIdNotFound() {
Optional<Event> event = eventService.getEventById("NONEXISTENT");
assertFalse(event.isPresent());
}
@Test
@DisplayName("测试更新事件状态")
void testUpdateEventStatus() {
Optional<Event> updated = eventService.updateEventStatus("EVT-001", EventStatus.PROCESSING);
assertTrue(updated.isPresent());
assertEquals(EventStatus.PROCESSING, updated.get().getStatus());
}
}

View File

@ -0,0 +1,102 @@
package com.example.demo;
import com.example.demo.model.TaskScheme;
import com.example.demo.model.dto.SchemeCompareDTO;
import com.example.demo.service.SchemeService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
/**
* 任务方案管理服务单元测试
* <p>
* 测试方案列表详情对比重构分发等核心业务逻辑
* </p>
*
* @requirement(name="集中式/分布式方案列表展示", id="SRS-TMS-01")
* @requirement(name="方案详情查看", id="SRS-TMS-03")
* @requirement(name="多方案对比分析", id="SRS-TMS-04")
* @requirement(name="方案重构操作", id="SRS-TMS-06")
* @requirement(name="方案分发驱动", id="SRS-TMS-08")
*/
@SpringBootTest
class SchemeServiceTest {
@Autowired
private SchemeService schemeService;
@Test
@DisplayName("测试查询方案列表")
void testListSchemes() {
List<TaskScheme> schemes = schemeService.listSchemes("createTime", "desc", 0, 10);
assertNotNull(schemes);
assertFalse(schemes.isEmpty());
}
@Test
@DisplayName("测试按优先级排序查询方案列表")
void testListSchemesSortedByPriority() {
List<TaskScheme> schemes = schemeService.listSchemes("priority", "desc", 0, 10);
assertNotNull(schemes);
if (schemes.size() >= 2) {
assertTrue(schemes.get(0).getPriority() >= schemes.get(1).getPriority());
}
}
@Test
@DisplayName("测试查询方案详情")
void testGetSchemeDetail() {
Optional<TaskScheme> scheme = schemeService.getSchemeDetail("SCH-001");
assertTrue(scheme.isPresent());
assertEquals("SCH-001", scheme.get().getSchemeId());
assertNotNull(scheme.get().getDeploymentDetail());
assertNotNull(scheme.get().getRouteDetail());
assertNotNull(scheme.get().getAlgorithmTrace());
}
@Test
@DisplayName("测试查询不存在的方案详情")
void testGetSchemeDetailNotFound() {
Optional<TaskScheme> scheme = schemeService.getSchemeDetail("NONEXISTENT");
assertFalse(scheme.isPresent());
}
@Test
@DisplayName("测试多方案对比分析")
void testCompareSchemes() {
SchemeCompareDTO dto = new SchemeCompareDTO();
dto.setSchemeIds(Arrays.asList("SCH-001", "SCH-002", "SCH-003"));
dto.setCompareFields(Arrays.asList("estimatedDuration", "estimatedLossRatio", "successRate", "priority"));
Map<String, Object> result = schemeService.compareSchemes(dto);
assertNotNull(result);
assertTrue(result.containsKey("schemes"));
}
@Test
@DisplayName("测试方案重构")
void testReconstructScheme() {
TaskScheme newScheme = schemeService.reconstructScheme("SCH-001", "{\"maxDuration\": 90}");
assertNotNull(newScheme);
assertNotNull(newScheme.getSchemeId());
assertEquals("SCH-001", newScheme.getParentSchemeId());
assertEquals(2, newScheme.getVersion()); // 原版本1重构后版本2
}
@Test
@DisplayName("测试方案分发")
void testDispatchScheme() {
Map<String, Object> result = schemeService.dispatchScheme("SCH-002", "NODE-A1");
assertNotNull(result);
assertEquals("SCH-002", result.get("schemeId"));
assertNotNull(result.get("instructions"));
}
}

View File

@ -0,0 +1,66 @@
package com.example.demo;
import com.example.demo.model.TaskDraft;
import com.example.demo.service.TaskGenerationService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
/**
* 任务生成服务单元测试
* <p>
* 测试任务草案生成发送与重试机制
* </p>
*
* @requirement(name="任务模板匹配与生成", id="SRS-EHTG-06")
* @requirement(name="任务草案发送与重试机制", id="SRS-EHTG-07")
*/
@SpringBootTest
class TaskGenerationServiceTest {
@Autowired
private TaskGenerationService taskGenerationService;
@Test
@DisplayName("测试基于事件生成任务草案")
void testGenerateTaskDraft() {
// EVT-002 CRITICAL 威胁 + 高置信度应能触发任务生成
TaskDraft draft = taskGenerationService.generateTaskDraft("EVT-002");
assertNotNull(draft);
assertNotNull(draft.getDraftId());
assertNotNull(draft.getTitle());
assertTrue(draft.getTargetValueScore() > 200);
assertEquals(0, draft.getSendStatus());
}
@Test
@DisplayName("测试低价值事件不会生成任务草案")
void testGenerateTaskDraftLowValue() {
// EVT-004 LOW 威胁 + 低置信度应无法触发任务生成
assertThrows(IllegalArgumentException.class, () -> {
taskGenerationService.generateTaskDraft("EVT-004");
});
}
@Test
@DisplayName("测试发送任务草案")
void testSendTaskDraft() {
TaskDraft draft = taskGenerationService.generateTaskDraft("EVT-001");
boolean result = taskGenerationService.sendTaskDraft(draft.getDraftId());
assertTrue(result);
}
@Test
@DisplayName("测试重试发送失败的任务草案")
void testRetrySendDraft() {
TaskDraft draft = taskGenerationService.generateTaskDraft("EVT-005");
// 先发送
taskGenerationService.sendTaskDraft(draft.getDraftId());
// 对于已成功发送的草案重试应返回 false无需重试
boolean retryResult = taskGenerationService.retrySendDraft(draft.getDraftId());
assertFalse(retryResult);
}
}