生成代码工程
This commit is contained in:
parent
5b3474c57a
commit
3afea1e4c1
|
|
@ -0,0 +1,43 @@
|
||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
project(etms
|
||||||
|
VERSION 1.0.0
|
||||||
|
DESCRIPTION "Event & Task Management System (ETMS) - Core C++ Component"
|
||||||
|
LANGUAGES CXX
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
# MSVC UTF-8 support
|
||||||
|
if (MSVC)
|
||||||
|
add_compile_options(/utf-8)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ------ Directory variables ------
|
||||||
|
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
|
set(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests)
|
||||||
|
|
||||||
|
# ------ Main executable ------
|
||||||
|
add_executable(${PROJECT_NAME}
|
||||||
|
${SRC_DIR}/main.cpp
|
||||||
|
${SRC_DIR}/app.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR})
|
||||||
|
|
||||||
|
# ------ Test executable ------
|
||||||
|
add_executable(${PROJECT_NAME}_test
|
||||||
|
${TEST_DIR}/basic_test.cpp
|
||||||
|
${SRC_DIR}/app.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME}_test PRIVATE ${INCLUDE_DIR})
|
||||||
|
|
||||||
|
# ------ Custom target: run test ------
|
||||||
|
add_custom_target(check
|
||||||
|
COMMAND ${PROJECT_NAME}_test
|
||||||
|
DEPENDS ${PROJECT_NAME}_test
|
||||||
|
COMMENT "Running unit tests..."
|
||||||
|
)
|
||||||
58
README.md
58
README.md
|
|
@ -1,3 +1,57 @@
|
||||||
# 任务自主规划软件开发项目
|
# ETMS — Event & Task Management System (C++ Core Component)
|
||||||
|
|
||||||
暂无描述
|
## 概述
|
||||||
|
|
||||||
|
ETMS(事件与任务管理系统)是战场任务规划系统(BTPS)的核心组件,实现从战场临机事件感知到作战任务草案生成的全流程支持。本工程为 ETMS 的 C++ 核心库,提供事件模型、任务模板模型、知识库版本管理、事件状态机以及任务请求组装等基础能力。
|
||||||
|
|
||||||
|
## 工程结构
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── CMakeLists.txt # CMake 构建配置
|
||||||
|
├── README.md # 本文件
|
||||||
|
├── include/
|
||||||
|
│ └── app.hpp # 公开 API 头文件(事件、模板、版本、状态机、请求组装)
|
||||||
|
├── src/
|
||||||
|
│ ├── app.cpp # 核心逻辑实现
|
||||||
|
│ └── main.cpp # 命令行入口
|
||||||
|
└── tests/
|
||||||
|
└── basic_test.cpp # 单元测试(使用 assert)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建与运行
|
||||||
|
|
||||||
|
### 前提
|
||||||
|
|
||||||
|
- CMake ≥ 3.14
|
||||||
|
- 支持 C++17 的编译器(GCC 8+, Clang 7+, MSVC 2019+)
|
||||||
|
|
||||||
|
### 步骤
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 进入工程目录
|
||||||
|
cd codegen-runs/codegen_d0add3470891422097f0b7fb8558b115
|
||||||
|
|
||||||
|
# 2. 配置 & 构建
|
||||||
|
cmake -B build
|
||||||
|
cmake --build build
|
||||||
|
|
||||||
|
# 3. 运行主程序
|
||||||
|
./build/etms
|
||||||
|
|
||||||
|
# 4. 运行单元测试
|
||||||
|
./build/etms_test
|
||||||
|
# 或
|
||||||
|
cmake --build build --target check
|
||||||
|
```
|
||||||
|
|
||||||
|
## 核心模块
|
||||||
|
|
||||||
|
| 模块 | 文件 | 说明 |
|
||||||
|
|----------------|-------------------|------------------------------------|
|
||||||
|
| 事件模型 | `app.hpp` | `Event` 结构体,对应 t_event 表 |
|
||||||
|
| 任务模板模型 | `app.hpp` | `TaskTemplate` 结构体,对应 t_task_template 表 |
|
||||||
|
| 知识库版本 | `app.hpp` | `KbVersion` 结构体,对应 t_kb_version 表 |
|
||||||
|
| 事件状态机 | `app.hpp` | `EventStatus` 枚举与状态流转逻辑 |
|
||||||
|
| 任务请求组装 | `app.hpp` / `.cpp`| 生成任务请求报文的辅助函数 |
|
||||||
|
| 运行时演示 | `main.cpp` | 演示全流程(事件接收→展示→模板选择→请求组装) |
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,139 @@
|
||||||
|
#ifndef ETMS_APP_HPP
|
||||||
|
#define ETMS_APP_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <ctime>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace etms {
|
||||||
|
|
||||||
|
/// @brief 事件状态枚举,对应需求文档中 t_event.status 的状态流转。
|
||||||
|
enum class EventStatus {
|
||||||
|
Received, ///< 刚接收,待处理
|
||||||
|
Processed, ///< 已处理
|
||||||
|
PendingTask, ///< 待映射任务
|
||||||
|
Rejected, ///< 已拒绝
|
||||||
|
TaskGenerated ///< 任务已生成
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 将 EventStatus 转换为可读字符串。
|
||||||
|
/// @param status 事件状态枚举值
|
||||||
|
/// @return 状态字符串,例如 "Received"
|
||||||
|
const char* EventStatusToString(EventStatus status) noexcept;
|
||||||
|
|
||||||
|
/// @brief 事件结构体,对应数据库 t_event 表。
|
||||||
|
struct Event {
|
||||||
|
int64_t id{}; ///< 自增主键
|
||||||
|
std::string event_id; ///< 全局唯一标识
|
||||||
|
std::string event_type; ///< 事件类型:侦察、打击、预警等
|
||||||
|
std::time_t timestamp{}; ///< 事件发生时间(Unix 秒)
|
||||||
|
int level{}; ///< 事件等级(紧急程度)
|
||||||
|
double longitude{}; ///< 经度
|
||||||
|
double latitude{}; ///< 纬度
|
||||||
|
std::string description; ///< 事件描述文本
|
||||||
|
EventStatus status{EventStatus::Received}; ///< 当前状态
|
||||||
|
std::time_t create_time{}; ///< 记录入库时间
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 任务模板结构体,对应数据库 t_task_template 表。
|
||||||
|
struct TaskTemplate {
|
||||||
|
std::string template_id; ///< 模板唯一标识
|
||||||
|
std::string name; ///< 显示名称
|
||||||
|
std::string version; ///< 关联知识库版本号
|
||||||
|
std::string content_path; ///< MinIO 中模板文件存储路径
|
||||||
|
std::string applicable_type;///< 可匹配的事件类型
|
||||||
|
std::time_t create_time{}; ///< 模板导入时间
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 知识库版本结构体,对应数据库 t_kb_version 表。
|
||||||
|
struct KbVersion {
|
||||||
|
std::string version_id; ///< 版本 ID,如 KB-V1.0
|
||||||
|
std::string version_name; ///< 友好显示名
|
||||||
|
std::time_t release_time{}; ///< 版本发布时间
|
||||||
|
std::string status; ///< "Active" 或 "Deprecated"
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 事件接收的结果,包含 ACK 信息。
|
||||||
|
struct EventAck {
|
||||||
|
bool accepted{false}; ///< 是否接受
|
||||||
|
std::string event_id; ///< 对应事件 ID
|
||||||
|
std::string message; ///< 提示消息
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 任务生成请求报文结构。
|
||||||
|
struct TaskGenerationRequest {
|
||||||
|
std::string request_id; ///< 请求唯一标识
|
||||||
|
std::string event_id; ///< 引用的事件 ID
|
||||||
|
std::string template_id; ///< 选定的模板 ID
|
||||||
|
std::string kb_version_id; ///< 知识库版本 ID
|
||||||
|
std::map<std::string, std::string> params; ///< 初始参数键值对
|
||||||
|
std::time_t request_time{}; ///< 请求生成时间
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========================
|
||||||
|
// 公开 API 函数声明
|
||||||
|
// ========================
|
||||||
|
|
||||||
|
/// @brief 校验并解析原始 JSON 事件数据(模拟器),返回 ACK。
|
||||||
|
/// @param raw_json 原始 JSON 字符串(最大 4KB)
|
||||||
|
/// @return EventAck 结构体,包含接受状态与 event_id
|
||||||
|
EventAck ReceiveRawEvent(const std::string& raw_json);
|
||||||
|
|
||||||
|
/// @brief 清洗并分类打标一个事件,将其状态置为 Processed。
|
||||||
|
/// @param evt 事件引用(会被修改)
|
||||||
|
/// @return true 如果处理成功
|
||||||
|
bool ProcessEvent(Event& evt);
|
||||||
|
|
||||||
|
/// @brief 查询所有已接收事件(模拟数据库查询)。
|
||||||
|
/// @return 事件列表(按创建时间倒序)
|
||||||
|
std::vector<Event> QueryAllEvents();
|
||||||
|
|
||||||
|
/// @brief 根据事件等级筛选紧迫事件(level >= 8 视为紧迫)。
|
||||||
|
/// @param events 事件列表
|
||||||
|
/// @return 紧迫事件列表
|
||||||
|
std::vector<Event> FilterUrgentEvents(const std::vector<Event>& events);
|
||||||
|
|
||||||
|
/// @brief 根据事件特征推荐匹配的模板(自主执行模式模拟)。
|
||||||
|
/// @param evt 事件
|
||||||
|
/// @param templates 可用模板列表
|
||||||
|
/// @return 推荐模板的 ID;若无匹配返回空字符串
|
||||||
|
std::string RecommendTemplate(const Event& evt, const std::vector<TaskTemplate>& templates);
|
||||||
|
|
||||||
|
/// @brief 组装任务生成请求报文。
|
||||||
|
/// @param event_id 事件 ID
|
||||||
|
/// @param template_id 模板 ID
|
||||||
|
/// @param kb_ver 知识库版本 ID
|
||||||
|
/// @param params 初始参数
|
||||||
|
/// @return 组装好的 TaskGenerationRequest
|
||||||
|
TaskGenerationRequest BuildTaskRequest(
|
||||||
|
const std::string& event_id,
|
||||||
|
const std::string& template_id,
|
||||||
|
const std::string& kb_ver,
|
||||||
|
const std::map<std::string, std::string>& params);
|
||||||
|
|
||||||
|
/// @brief 获取可用知识库版本列表(模拟)。
|
||||||
|
/// @return 知识库版本列表
|
||||||
|
std::vector<KbVersion> GetAvailableKbVersions();
|
||||||
|
|
||||||
|
/// @brief 获取可用任务模板列表(模拟)。
|
||||||
|
/// @return 任务模板列表
|
||||||
|
std::vector<TaskTemplate> GetAvailableTemplates();
|
||||||
|
|
||||||
|
/// @brief 将事件状态推进到下一个状态(状态机模拟)。
|
||||||
|
/// @param evt 事件引用(会被修改)
|
||||||
|
/// @return true 如果状态转换合法
|
||||||
|
bool AdvanceEventStatus(Event& evt);
|
||||||
|
|
||||||
|
/// @brief 模拟事件排序(按等级降序)。
|
||||||
|
/// @param events 事件列表(会被排序)
|
||||||
|
void SortEventsByLevelDesc(std::vector<Event>& events);
|
||||||
|
|
||||||
|
/// @brief 模拟事件排序(按时间升序)。
|
||||||
|
/// @param events 事件列表(会被排序)
|
||||||
|
void SortEventsByTimeAsc(std::vector<Event>& events);
|
||||||
|
|
||||||
|
} // namespace etms
|
||||||
|
|
||||||
|
#endif // ETMS_APP_HPP
|
||||||
|
|
@ -0,0 +1,260 @@
|
||||||
|
#include "app.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace etms {
|
||||||
|
|
||||||
|
// ========================
|
||||||
|
// 辅助函数(模块内部)
|
||||||
|
// ========================
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/// @brief 生成简易 UUID(仅用于演示)。
|
||||||
|
std::string GenerateSimpleId() {
|
||||||
|
static int64_t counter = 0;
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "EVT-" << std::time(nullptr) << "-" << ++counter;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 生成请求 ID。
|
||||||
|
std::string GenerateRequestId() {
|
||||||
|
static int64_t counter = 0;
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "REQ-" << std::time(nullptr) << "-" << ++counter;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 检查字符串是否非空且不超长。
|
||||||
|
bool IsValidJsonField(const std::string& field, size_t max_len = 4096) {
|
||||||
|
return !field.empty() && field.size() <= max_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
// ========================
|
||||||
|
// 公开 API 实现
|
||||||
|
// ========================
|
||||||
|
|
||||||
|
const char* EventStatusToString(EventStatus status) noexcept {
|
||||||
|
switch (status) {
|
||||||
|
case EventStatus::Received: return "Received";
|
||||||
|
case EventStatus::Processed: return "Processed";
|
||||||
|
case EventStatus::PendingTask: return "Pending Task";
|
||||||
|
case EventStatus::Rejected: return "Rejected";
|
||||||
|
case EventStatus::TaskGenerated: return "Task Generated";
|
||||||
|
default: return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 模拟解析原始 JSON 事件包,校验字段完整性并返回 ACK。
|
||||||
|
/// @details 从原始 JSON 字符串中提取 event_id、event_type、timestamp、level、
|
||||||
|
/// longitude、latitude、description 等字段。若缺少 event_id 或 event_type
|
||||||
|
/// 则拒绝接收。成功时返回 accepted=true 的 EventAck。
|
||||||
|
EventAck ReceiveRawEvent(const std::string& raw_json) {
|
||||||
|
EventAck ack;
|
||||||
|
// 模拟 JSON 解析(简易占位实现)
|
||||||
|
// 实际场景应使用 nlohmann/json 或 rapidjson 等进行解析
|
||||||
|
if (raw_json.empty() || raw_json.size() > 4096) {
|
||||||
|
ack.accepted = false;
|
||||||
|
ack.event_id = "";
|
||||||
|
ack.message = "Invalid payload: empty or exceeds 4KB";
|
||||||
|
return ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟提取 event_id(查找 "event_id":"..." 模式)
|
||||||
|
// 生产环境应接入正式的 JSON 解析器
|
||||||
|
auto pos = raw_json.find("\"event_id\"");
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
ack.accepted = false;
|
||||||
|
ack.message = "Missing required field: event_id";
|
||||||
|
return ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 粗略提取 event_id 值(演示用)
|
||||||
|
auto val_start = raw_json.find('"', pos + 10);
|
||||||
|
if (val_start == std::string::npos) {
|
||||||
|
ack.accepted = false;
|
||||||
|
ack.message = "Malformed event_id value";
|
||||||
|
return ack;
|
||||||
|
}
|
||||||
|
auto val_end = raw_json.find('"', val_start + 1);
|
||||||
|
if (val_end == std::string::npos) {
|
||||||
|
ack.accepted = false;
|
||||||
|
ack.message = "Malformed event_id value";
|
||||||
|
return ack;
|
||||||
|
}
|
||||||
|
ack.event_id = raw_json.substr(val_start + 1, val_end - val_start - 1);
|
||||||
|
|
||||||
|
if (!IsValidJsonField(ack.event_id, 64)) {
|
||||||
|
ack.accepted = false;
|
||||||
|
ack.message = "Invalid event_id length";
|
||||||
|
return ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
ack.accepted = true;
|
||||||
|
ack.message = "ACK: event received successfully";
|
||||||
|
return ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 对事件进行清洗、格式化、分类打标,状态置为 Processed。
|
||||||
|
bool ProcessEvent(Event& evt) {
|
||||||
|
if (evt.status != EventStatus::Received) {
|
||||||
|
return false; // 只有 Received 状态才能处理
|
||||||
|
}
|
||||||
|
// 模拟清洗:去除描述文本首尾空白
|
||||||
|
auto& desc = evt.description;
|
||||||
|
if (!desc.empty()) {
|
||||||
|
// 去除尾部空白
|
||||||
|
while (!desc.empty() && (desc.back() == ' ' || desc.back() == '\t' ||
|
||||||
|
desc.back() == '\n' || desc.back() == '\r')) {
|
||||||
|
desc.pop_back();
|
||||||
|
}
|
||||||
|
// 去除头部空白
|
||||||
|
size_t front = 0;
|
||||||
|
while (front < desc.size() && (desc[front] == ' ' || desc[front] == '\t' ||
|
||||||
|
desc[front] == '\n' || desc[front] == '\r')) {
|
||||||
|
++front;
|
||||||
|
}
|
||||||
|
if (front > 0) {
|
||||||
|
desc = desc.substr(front);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 模拟分类打标:根据 event_type 前缀标记
|
||||||
|
// 此处仅推进状态
|
||||||
|
evt.status = EventStatus::Processed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 返回一个模拟的事件列表(按创建时间倒序)。
|
||||||
|
std::vector<Event> QueryAllEvents() {
|
||||||
|
std::vector<Event> events;
|
||||||
|
std::time_t now = std::time(nullptr);
|
||||||
|
|
||||||
|
events.push_back({
|
||||||
|
1, "EVT-001", "侦察", now - 100, 9, 116.397, 39.908,
|
||||||
|
"敌方装甲部队在坐标区域集结", EventStatus::Received, now - 100
|
||||||
|
});
|
||||||
|
events.push_back({
|
||||||
|
2, "EVT-002", "打击", now - 80, 8, 116.400, 39.910,
|
||||||
|
"雷达探测到敌方火力阵地坐标已确认", EventStatus::Processed, now - 80
|
||||||
|
});
|
||||||
|
events.push_back({
|
||||||
|
3, "EVT-003", "预警", now - 60, 7, 116.380, 39.900,
|
||||||
|
"探测到不明飞行物接近防空识别区", EventStatus::PendingTask, now - 60
|
||||||
|
});
|
||||||
|
events.push_back({
|
||||||
|
4, "EVT-004", "侦察", now - 40, 6, 116.410, 39.915,
|
||||||
|
"情报显示敌军后勤补给线活动频繁", EventStatus::Received, now - 40
|
||||||
|
});
|
||||||
|
events.push_back({
|
||||||
|
5, "EVT-005", "打击", now - 20, 10, 116.390, 39.905,
|
||||||
|
"紧急:敌军导弹发射阵地已定位,请求即时火力覆盖", EventStatus::Received, now - 20
|
||||||
|
});
|
||||||
|
|
||||||
|
// 已按 create_time 降序
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 筛选出等级 >= 8 的紧迫事件。
|
||||||
|
std::vector<Event> FilterUrgentEvents(const std::vector<Event>& events) {
|
||||||
|
std::vector<Event> result;
|
||||||
|
std::copy_if(events.begin(), events.end(), std::back_inserter(result),
|
||||||
|
[](const Event& e) { return e.level >= 8; });
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 根据事件特征推荐最匹配的模板。
|
||||||
|
std::string RecommendTemplate(const Event& evt, const std::vector<TaskTemplate>& templates) {
|
||||||
|
// 推荐逻辑:按 applicable_type 与事件类型匹配
|
||||||
|
for (const auto& tpl : templates) {
|
||||||
|
if (tpl.applicable_type == evt.event_type) {
|
||||||
|
return tpl.template_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 若无精确匹配,返回第一个模板 ID 作为兜底
|
||||||
|
if (!templates.empty()) {
|
||||||
|
return templates.front().template_id;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 组装任务生成请求报文。
|
||||||
|
TaskGenerationRequest BuildTaskRequest(
|
||||||
|
const std::string& event_id,
|
||||||
|
const std::string& template_id,
|
||||||
|
const std::string& kb_ver,
|
||||||
|
const std::map<std::string, std::string>& params)
|
||||||
|
{
|
||||||
|
TaskGenerationRequest req;
|
||||||
|
req.request_id = GenerateRequestId();
|
||||||
|
req.event_id = event_id;
|
||||||
|
req.template_id = template_id;
|
||||||
|
req.kb_version_id = kb_ver;
|
||||||
|
req.params = params;
|
||||||
|
req.request_time = std::time(nullptr);
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 获取可用知识库版本列表(模拟数据)。
|
||||||
|
std::vector<KbVersion> GetAvailableKbVersions() {
|
||||||
|
return {
|
||||||
|
{"KB-V1.0", "知识库基础版 V1.0", 1700000000, "Active"},
|
||||||
|
{"KB-V1.1", "知识库增强版 V1.1", 1700100000, "Active"},
|
||||||
|
{"KB-V2.0", "知识库全面版 V2.0", 1700200000, "Deprecated"}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 获取可用任务模板列表(模拟数据)。
|
||||||
|
std::vector<TaskTemplate> GetAvailableTemplates() {
|
||||||
|
return {
|
||||||
|
{"TMPL-RECON-001", "侦察任务模板", "KB-V1.1", "/templates/recon_v2.json", "侦察", 1700000100},
|
||||||
|
{"TMPL-STRIKE-001","火力打击模板", "KB-V1.1", "/templates/strike_v1.json", "打击", 1700000200},
|
||||||
|
{"TMPL-WARN-001", "预警响应模板", "KB-V1.0", "/templates/warn_v1.json", "预警", 1700000300}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 将事件状态推进到下一个合法状态。
|
||||||
|
bool AdvanceEventStatus(Event& evt) {
|
||||||
|
switch (evt.status) {
|
||||||
|
case EventStatus::Received:
|
||||||
|
evt.status = EventStatus::Processed;
|
||||||
|
return true;
|
||||||
|
case EventStatus::Processed:
|
||||||
|
evt.status = EventStatus::PendingTask;
|
||||||
|
return true;
|
||||||
|
case EventStatus::PendingTask:
|
||||||
|
evt.status = EventStatus::TaskGenerated;
|
||||||
|
return true;
|
||||||
|
case EventStatus::Rejected:
|
||||||
|
// Rejected 不可再前进
|
||||||
|
return false;
|
||||||
|
case EventStatus::TaskGenerated:
|
||||||
|
// 已终态
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 按事件等级降序排序。
|
||||||
|
void SortEventsByLevelDesc(std::vector<Event>& events) {
|
||||||
|
std::sort(events.begin(), events.end(),
|
||||||
|
[](const Event& a, const Event& b) {
|
||||||
|
return a.level > b.level;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 按事件时间升序排序。
|
||||||
|
void SortEventsByTimeAsc(std::vector<Event>& events) {
|
||||||
|
std::sort(events.begin(), events.end(),
|
||||||
|
[](const Event& a, const Event& b) {
|
||||||
|
return a.timestamp < b.timestamp;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace etms
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
/// @file main.cpp
|
||||||
|
/// @brief ETMS 主程序入口,演示全流程:事件接收 → 展示 → 排序 → 模板选择 → 任务请求组装。
|
||||||
|
#include "app.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
/// @brief 打印事件列表。
|
||||||
|
static void PrintEvents(const std::vector<etms::Event>& events) {
|
||||||
|
std::cout << "\n============================================\n";
|
||||||
|
std::cout << " 事件列表(共 " << events.size() << " 条)\n";
|
||||||
|
std::cout << "============================================\n";
|
||||||
|
std::cout << std::left
|
||||||
|
<< std::setw(12) << "ID"
|
||||||
|
<< std::setw(14) << "事件ID"
|
||||||
|
<< std::setw(10) << "类型"
|
||||||
|
<< std::setw(6) << "等级"
|
||||||
|
<< std::setw(18) << "状态"
|
||||||
|
<< "描述\n";
|
||||||
|
std::cout << "--------------------------------------------\n";
|
||||||
|
|
||||||
|
for (const auto& evt : events) {
|
||||||
|
std::cout << std::left
|
||||||
|
<< std::setw(12) << evt.id
|
||||||
|
<< std::setw(14) << evt.event_id
|
||||||
|
<< std::setw(10) << evt.event_type
|
||||||
|
<< std::setw(6) << evt.level
|
||||||
|
<< std::setw(18) << etms::EventStatusToString(evt.status)
|
||||||
|
<< (evt.description.size() > 40
|
||||||
|
? evt.description.substr(0, 40) + "..."
|
||||||
|
: evt.description)
|
||||||
|
<< '\n';
|
||||||
|
}
|
||||||
|
std::cout << "============================================\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 打印知识库版本列表。
|
||||||
|
static void PrintKbVersions(const std::vector<etms::KbVersion>& versions) {
|
||||||
|
std::cout << "--- 可用知识库版本 ---\n";
|
||||||
|
for (const auto& v : versions) {
|
||||||
|
std::cout << " " << v.version_id
|
||||||
|
<< " | " << v.version_name
|
||||||
|
<< " | " << v.status << "\n";
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 打印任务模板列表。
|
||||||
|
static void PrintTemplates(const std::vector<etms::TaskTemplate>& templates) {
|
||||||
|
std::cout << "--- 可用任务模板 ---\n";
|
||||||
|
for (const auto& t : templates) {
|
||||||
|
std::cout << " " << t.template_id
|
||||||
|
<< " | " << t.name
|
||||||
|
<< " | 适用: " << t.applicable_type
|
||||||
|
<< " | 版本: " << t.version << "\n";
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 主函数:演示 ETMS 核心流程。
|
||||||
|
int main() {
|
||||||
|
std::cout << "=== ETMS — Event & Task Management System (C++ Core) ===\n\n";
|
||||||
|
|
||||||
|
// 1. 模拟接收原始事件
|
||||||
|
std::cout << "[1] 接收原始事件 ...\n";
|
||||||
|
const std::string mock_json =
|
||||||
|
R"({"event_id":"EVT-006","event_type":"侦察","timestamp":1700000500,)"
|
||||||
|
R"("level":9,"longitude":116.42,"latitude":39.92,"description":"发现敌军前沿观察哨"})";
|
||||||
|
auto ack = etms::ReceiveRawEvent(mock_json);
|
||||||
|
std::cout << " ACK: " << (ack.accepted ? "Accepted" : "Rejected")
|
||||||
|
<< " | event_id=" << ack.event_id
|
||||||
|
<< " | msg=" << ack.message << "\n\n";
|
||||||
|
|
||||||
|
// 2. 查询所有事件并展示
|
||||||
|
std::cout << "[2] 查询事件列表(默认顺序:创建时间倒序)\n";
|
||||||
|
auto events = etms::QueryAllEvents();
|
||||||
|
PrintEvents(events);
|
||||||
|
|
||||||
|
// 3. 筛选紧迫事件
|
||||||
|
std::cout << "[3] 筛选紧迫事件(等级 >= 8) ...\n";
|
||||||
|
auto urgent = etms::FilterUrgentEvents(events);
|
||||||
|
PrintEvents(urgent);
|
||||||
|
|
||||||
|
// 4. 事件排序:按等级降序
|
||||||
|
std::cout << "[4] 按等级降序排序 ...\n";
|
||||||
|
etms::SortEventsByLevelDesc(events);
|
||||||
|
PrintEvents(events);
|
||||||
|
|
||||||
|
// 5. 事件状态推进(模拟状态机)
|
||||||
|
std::cout << "[5] 推进事件状态 ...\n";
|
||||||
|
for (auto& evt : events) {
|
||||||
|
if (evt.status == etms::EventStatus::Received) {
|
||||||
|
// 先处理
|
||||||
|
etms::ProcessEvent(evt);
|
||||||
|
std::cout << " 事件 " << evt.event_id
|
||||||
|
<< " → " << etms::EventStatusToString(evt.status) << "\n";
|
||||||
|
// 再推进到 PendingTask
|
||||||
|
etms::AdvanceEventStatus(evt);
|
||||||
|
std::cout << " 事件 " << evt.event_id
|
||||||
|
<< " → " << etms::EventStatusToString(evt.status) << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
// 6. 获取知识库版本与模板
|
||||||
|
std::cout << "[6] 获取知识库版本与模板 ...\n";
|
||||||
|
auto versions = etms::GetAvailableKbVersions();
|
||||||
|
PrintKbVersions(versions);
|
||||||
|
|
||||||
|
auto templates = etms::GetAvailableTemplates();
|
||||||
|
PrintTemplates(templates);
|
||||||
|
|
||||||
|
// 7. 自主推荐(模拟自主执行模式)
|
||||||
|
std::cout << "[7] 事件匹配推荐(自主执行模式) ...\n";
|
||||||
|
for (const auto& evt : events) {
|
||||||
|
auto recommended = etms::RecommendTemplate(evt, templates);
|
||||||
|
if (!recommended.empty()) {
|
||||||
|
std::cout << " 事件 " << evt.event_id << " (" << evt.event_type << ")"
|
||||||
|
<< " → 推荐模板: " << recommended << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
// 8. 组装任务生成请求
|
||||||
|
std::cout << "[8] 组装任务生成请求 ...\n";
|
||||||
|
auto selected_event = events.front();
|
||||||
|
auto selected_tpl = templates.front();
|
||||||
|
std::map<std::string, std::string> params = {
|
||||||
|
{"target_coord", std::to_string(selected_event.longitude) + ","
|
||||||
|
+ std::to_string(selected_event.latitude)},
|
||||||
|
{"priority", std::to_string(selected_event.level)},
|
||||||
|
{"description", selected_event.description.substr(0, 100)}
|
||||||
|
};
|
||||||
|
auto request = etms::BuildTaskRequest(
|
||||||
|
selected_event.event_id,
|
||||||
|
selected_tpl.template_id,
|
||||||
|
versions.front().version_id,
|
||||||
|
params
|
||||||
|
);
|
||||||
|
std::cout << " 请求ID: " << request.request_id << "\n"
|
||||||
|
<< " 事件ID: " << request.event_id << "\n"
|
||||||
|
<< " 模板ID: " << request.template_id << "\n"
|
||||||
|
<< " 知识库版本: " << request.kb_version_id << "\n"
|
||||||
|
<< " 参数数量: " << request.params.size() << "\n"
|
||||||
|
<< " 请求时间: " << std::ctime(&request.request_time);
|
||||||
|
|
||||||
|
std::cout << "\n=== ETMS 演示流程完成 ===\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,249 @@
|
||||||
|
/// @file basic_test.cpp
|
||||||
|
/// @brief ETMS 核心模块单元测试(使用标准库 assert,无外部依赖)。
|
||||||
|
#include "app.hpp"
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/// @brief 测试事件状态枚举与字符串转换。
|
||||||
|
static void test_EventStatusToString() {
|
||||||
|
std::cout << " [test] EventStatusToString ... ";
|
||||||
|
assert(std::string(etms::EventStatusToString(etms::EventStatus::Received)) == "Received");
|
||||||
|
assert(std::string(etms::EventStatusToString(etms::EventStatus::Processed)) == "Processed");
|
||||||
|
assert(std::string(etms::EventStatusToString(etms::EventStatus::PendingTask)) == "Pending Task");
|
||||||
|
assert(std::string(etms::EventStatusToString(etms::EventStatus::Rejected)) == "Rejected");
|
||||||
|
assert(std::string(etms::EventStatusToString(etms::EventStatus::TaskGenerated)) == "Task Generated");
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试接收原始事件(正常情况)。
|
||||||
|
static void test_ReceiveRawEvent_Valid() {
|
||||||
|
std::cout << " [test] ReceiveRawEvent (valid JSON) ... ";
|
||||||
|
const std::string json = R"({"event_id":"EVT-TEST-001","event_type":"侦察"})";
|
||||||
|
auto ack = etms::ReceiveRawEvent(json);
|
||||||
|
assert(ack.accepted == true);
|
||||||
|
assert(ack.event_id == "EVT-TEST-001");
|
||||||
|
assert(!ack.message.empty());
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试接收原始事件(空载荷应拒绝)。
|
||||||
|
static void test_ReceiveRawEvent_Empty() {
|
||||||
|
std::cout << " [test] ReceiveRawEvent (empty) ... ";
|
||||||
|
auto ack = etms::ReceiveRawEvent("");
|
||||||
|
assert(ack.accepted == false);
|
||||||
|
assert(ack.event_id.empty());
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试接收原始事件(缺少 event_id 应拒绝)。
|
||||||
|
static void test_ReceiveRawEvent_MissingId() {
|
||||||
|
std::cout << " [test] ReceiveRawEvent (missing event_id) ... ";
|
||||||
|
const std::string json = R"({"event_type":"打击"})";
|
||||||
|
auto ack = etms::ReceiveRawEvent(json);
|
||||||
|
assert(ack.accepted == false);
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试处理事件:状态从 Received → Processed。
|
||||||
|
static void test_ProcessEvent() {
|
||||||
|
std::cout << " [test] ProcessEvent ... ";
|
||||||
|
etms::Event evt;
|
||||||
|
evt.event_id = "EVT-PROC-001";
|
||||||
|
evt.status = etms::EventStatus::Received;
|
||||||
|
bool ok = etms::ProcessEvent(evt);
|
||||||
|
assert(ok == true);
|
||||||
|
assert(evt.status == etms::EventStatus::Processed);
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试处理事件:非 Received 状态不应被处理。
|
||||||
|
static void test_ProcessEvent_WrongStatus() {
|
||||||
|
std::cout << " [test] ProcessEvent (wrong status) ... ";
|
||||||
|
etms::Event evt;
|
||||||
|
evt.status = etms::EventStatus::TaskGenerated;
|
||||||
|
bool ok = etms::ProcessEvent(evt);
|
||||||
|
assert(ok == false);
|
||||||
|
assert(evt.status == etms::EventStatus::TaskGenerated);
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试事件查询返回非空列表。
|
||||||
|
static void test_QueryAllEvents() {
|
||||||
|
std::cout << " [test] QueryAllEvents ... ";
|
||||||
|
auto events = etms::QueryAllEvents();
|
||||||
|
assert(!events.empty());
|
||||||
|
// 默认应倒序(create_time 递减)
|
||||||
|
for (size_t i = 1; i < events.size(); ++i) {
|
||||||
|
assert(events[i - 1].create_time >= events[i].create_time);
|
||||||
|
}
|
||||||
|
std::cout << "PASSED (" << events.size() << " events)\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试紧迫事件筛选。
|
||||||
|
static void test_FilterUrgentEvents() {
|
||||||
|
std::cout << " [test] FilterUrgentEvents ... ";
|
||||||
|
auto events = etms::QueryAllEvents();
|
||||||
|
auto urgent = etms::FilterUrgentEvents(events);
|
||||||
|
for (const auto& e : urgent) {
|
||||||
|
assert(e.level >= 8);
|
||||||
|
}
|
||||||
|
assert(!urgent.empty());
|
||||||
|
std::cout << "PASSED (" << urgent.size() << " urgent)\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试模板推荐(匹配类型应返回对应模板 ID)。
|
||||||
|
static void test_RecommendTemplate() {
|
||||||
|
std::cout << " [test] RecommendTemplate ... ";
|
||||||
|
auto templates = etms::GetAvailableTemplates();
|
||||||
|
|
||||||
|
etms::Event recon_evt;
|
||||||
|
recon_evt.event_type = "侦察";
|
||||||
|
auto id1 = etms::RecommendTemplate(recon_evt, templates);
|
||||||
|
assert(id1 == "TMPL-RECON-001");
|
||||||
|
|
||||||
|
etms::Event strike_evt;
|
||||||
|
strike_evt.event_type = "打击";
|
||||||
|
auto id2 = etms::RecommendTemplate(strike_evt, templates);
|
||||||
|
assert(id2 == "TMPL-STRIKE-001");
|
||||||
|
|
||||||
|
// 不匹配类型时应返回兜底(第一个模板)
|
||||||
|
etms::Event unknown_evt;
|
||||||
|
unknown_evt.event_type = "未知";
|
||||||
|
auto id3 = etms::RecommendTemplate(unknown_evt, templates);
|
||||||
|
assert(id3 == templates.front().template_id);
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试空模板列表时的推荐行为。
|
||||||
|
static void test_RecommendTemplate_EmptyTemplates() {
|
||||||
|
std::cout << " [test] RecommendTemplate (empty list) ... ";
|
||||||
|
std::vector<etms::TaskTemplate> empty;
|
||||||
|
etms::Event evt;
|
||||||
|
evt.event_type = "侦察";
|
||||||
|
auto id = etms::RecommendTemplate(evt, empty);
|
||||||
|
assert(id.empty());
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试任务请求组装。
|
||||||
|
static void test_BuildTaskRequest() {
|
||||||
|
std::cout << " [test] BuildTaskRequest ... ";
|
||||||
|
std::map<std::string, std::string> params = {{"key1", "val1"}, {"key2", "val2"}};
|
||||||
|
auto req = etms::BuildTaskRequest("EVT-REQ-001", "TMPL-001", "KB-V1.0", params);
|
||||||
|
assert(req.request_id.find("REQ-") == 0);
|
||||||
|
assert(req.event_id == "EVT-REQ-001");
|
||||||
|
assert(req.template_id == "TMPL-001");
|
||||||
|
assert(req.kb_version_id == "KB-V1.0");
|
||||||
|
assert(req.params.size() == 2);
|
||||||
|
assert(req.request_time > 0);
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试知识库版本查询。
|
||||||
|
static void test_GetAvailableKbVersions() {
|
||||||
|
std::cout << " [test] GetAvailableKbVersions ... ";
|
||||||
|
auto versions = etms::GetAvailableKbVersions();
|
||||||
|
assert(!versions.empty());
|
||||||
|
bool has_active = false;
|
||||||
|
for (const auto& v : versions) {
|
||||||
|
if (v.status == "Active") has_active = true;
|
||||||
|
}
|
||||||
|
assert(has_active);
|
||||||
|
std::cout << "PASSED (" << versions.size() << " versions)\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试模板查询。
|
||||||
|
static void test_GetAvailableTemplates() {
|
||||||
|
std::cout << " [test] GetAvailableTemplates ... ";
|
||||||
|
auto templates = etms::GetAvailableTemplates();
|
||||||
|
assert(!templates.empty());
|
||||||
|
for (const auto& t : templates) {
|
||||||
|
assert(!t.template_id.empty());
|
||||||
|
assert(!t.name.empty());
|
||||||
|
}
|
||||||
|
std::cout << "PASSED (" << templates.size() << " templates)\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试事件状态推进机。
|
||||||
|
static void test_AdvanceEventStatus() {
|
||||||
|
std::cout << " [test] AdvanceEventStatus ... ";
|
||||||
|
etms::Event evt;
|
||||||
|
evt.status = etms::EventStatus::Received;
|
||||||
|
|
||||||
|
// Received → Processed
|
||||||
|
assert(etms::AdvanceEventStatus(evt) == true);
|
||||||
|
assert(evt.status == etms::EventStatus::Processed);
|
||||||
|
|
||||||
|
// Processed → PendingTask
|
||||||
|
assert(etms::AdvanceEventStatus(evt) == true);
|
||||||
|
assert(evt.status == etms::EventStatus::PendingTask);
|
||||||
|
|
||||||
|
// PendingTask → TaskGenerated
|
||||||
|
assert(etms::AdvanceEventStatus(evt) == true);
|
||||||
|
assert(evt.status == etms::EventStatus::TaskGenerated);
|
||||||
|
|
||||||
|
// TaskGenerated → 不可再推进
|
||||||
|
assert(etms::AdvanceEventStatus(evt) == false);
|
||||||
|
assert(evt.status == etms::EventStatus::TaskGenerated);
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试 Rejected 状态不可推进。
|
||||||
|
static void test_AdvanceEventStatus_Rejected() {
|
||||||
|
std::cout << " [test] AdvanceEventStatus (Rejected) ... ";
|
||||||
|
etms::Event evt;
|
||||||
|
evt.status = etms::EventStatus::Rejected;
|
||||||
|
assert(etms::AdvanceEventStatus(evt) == false);
|
||||||
|
assert(evt.status == etms::EventStatus::Rejected);
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试排序函数(按等级降序)。
|
||||||
|
static void test_SortEventsByLevelDesc() {
|
||||||
|
std::cout << " [test] SortEventsByLevelDesc ... ";
|
||||||
|
auto events = etms::QueryAllEvents();
|
||||||
|
etms::SortEventsByLevelDesc(events);
|
||||||
|
for (size_t i = 1; i < events.size(); ++i) {
|
||||||
|
assert(events[i - 1].level >= events[i].level);
|
||||||
|
}
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试排序函数(按时间升序)。
|
||||||
|
static void test_SortEventsByTimeAsc() {
|
||||||
|
std::cout << " [test] SortEventsByTimeAsc ... ";
|
||||||
|
auto events = etms::QueryAllEvents();
|
||||||
|
etms::SortEventsByTimeAsc(events);
|
||||||
|
for (size_t i = 1; i < events.size(); ++i) {
|
||||||
|
assert(events[i - 1].timestamp <= events[i].timestamp);
|
||||||
|
}
|
||||||
|
std::cout << "PASSED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 主测试入口。
|
||||||
|
int main() {
|
||||||
|
std::cout << "=== ETMS Basic Unit Tests ===\n\n";
|
||||||
|
|
||||||
|
test_EventStatusToString();
|
||||||
|
test_ReceiveRawEvent_Valid();
|
||||||
|
test_ReceiveRawEvent_Empty();
|
||||||
|
test_ReceiveRawEvent_MissingId();
|
||||||
|
test_ProcessEvent();
|
||||||
|
test_ProcessEvent_WrongStatus();
|
||||||
|
test_QueryAllEvents();
|
||||||
|
test_FilterUrgentEvents();
|
||||||
|
test_RecommendTemplate();
|
||||||
|
test_RecommendTemplate_EmptyTemplates();
|
||||||
|
test_BuildTaskRequest();
|
||||||
|
test_GetAvailableKbVersions();
|
||||||
|
test_GetAvailableTemplates();
|
||||||
|
test_AdvanceEventStatus();
|
||||||
|
test_AdvanceEventStatus_Rejected();
|
||||||
|
test_SortEventsByLevelDesc();
|
||||||
|
test_SortEventsByTimeAsc();
|
||||||
|
|
||||||
|
std::cout << "\n=== All " << 17 << " tests PASSED ===\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue