功能开发
This commit is contained in:
parent
c6be24394e
commit
4b7a402ef7
|
|
@ -0,0 +1,24 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
project(BattlefieldMissionPlanner VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# MSVC UTF-8 编译选项
|
||||
if (MSVC)
|
||||
add_compile_options(/utf-8)
|
||||
endif()
|
||||
|
||||
# 主程序
|
||||
add_executable(bmp_main
|
||||
src/main.cpp
|
||||
src/app.cpp
|
||||
)
|
||||
target_include_directories(bmp_main PRIVATE include)
|
||||
|
||||
# 测试程序
|
||||
add_executable(bmp_test
|
||||
tests/basic_test.cpp
|
||||
src/app.cpp
|
||||
)
|
||||
target_include_directories(bmp_test PRIVATE include)
|
||||
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,564 @@
|
|||
#ifndef APP_HPP
|
||||
#define APP_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <cstdint>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
|
||||
/**
|
||||
* @brief 核心命名空间,包含战场任务规划管理系统的所有组件。
|
||||
*/
|
||||
namespace bmp {
|
||||
|
||||
// ============================================================================
|
||||
// 数据结构定义
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 事件状态枚举
|
||||
*
|
||||
* @requirement(name="事件接收与处理", id="SU-01")
|
||||
* 定义事件从接收到处理完成的生命周期状态。
|
||||
*/
|
||||
enum class EventStatus {
|
||||
PENDING, ///< 待处理
|
||||
PROCESSING, ///< 处理中
|
||||
ACCEPTED, ///< 已接受
|
||||
REJECTED, ///< 已拒绝
|
||||
ERROR ///< 处理异常
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 事件优先级枚举
|
||||
*/
|
||||
enum class EventPriority {
|
||||
LOW = 0,
|
||||
NORMAL = 1,
|
||||
HIGH = 2,
|
||||
CRITICAL = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 任务计划状态枚举
|
||||
*
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 定义计划从生成到完成的各个阶段状态。
|
||||
*/
|
||||
enum class PlanStatus {
|
||||
DRAFT, ///< 草稿
|
||||
CONFIRMED, ///< 已确认
|
||||
DISTRIBUTING, ///< 分发中
|
||||
EXECUTING, ///< 执行中
|
||||
COMPLETED, ///< 已完成
|
||||
FAILED, ///< 失败
|
||||
CANCELLED ///< 已取消
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 资产状态枚举
|
||||
*
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 定义遥测数据中资产运行状态的分类。
|
||||
*/
|
||||
enum class AssetStatus {
|
||||
ONLINE, ///< 在线
|
||||
OFFLINE, ///< 离线
|
||||
BUSY, ///< 忙碌
|
||||
ERROR, ///< 故障
|
||||
STALE ///< 数据陈旧
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 分发响应状态枚举
|
||||
*
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 定义任务分发后的资产响应状态。
|
||||
*/
|
||||
enum class DistributionResponse {
|
||||
ACK, ///< 确认收到
|
||||
NACK, ///< 否定确认
|
||||
TIMEOUT, ///< 超时
|
||||
ERROR ///< 协议错误
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 事件数据结构
|
||||
*
|
||||
* @requirement(name="事件接收与处理", id="SU-01")
|
||||
* 表示从上游系统接收的原始事件,经过标准化处理后存储。
|
||||
*/
|
||||
struct Event {
|
||||
std::string id; ///< 事件ID
|
||||
std::string type; ///< 事件类型
|
||||
std::string title; ///< 事件标题
|
||||
std::string description; ///< 事件描述
|
||||
double latitude = 0.0; ///< 纬度坐标
|
||||
double longitude = 0.0; ///< 经度坐标
|
||||
EventPriority priority = EventPriority::NORMAL; ///< 优先级
|
||||
EventStatus status = EventStatus::PENDING; ///< 当前状态
|
||||
std::string rawData; ///< 原始JSON/XML数据
|
||||
std::string receiveNodeId; ///< 接收节点ID
|
||||
std::chrono::system_clock::time_point occurTime; ///< 发生时间
|
||||
std::chrono::system_clock::time_point createTime; ///< 创建时间
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 任务模板数据结构
|
||||
*
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 表示系统从模板服务接收的任务模板,包含版本控制信息。
|
||||
*/
|
||||
struct TaskTemplate {
|
||||
std::string id; ///< 模板ID
|
||||
std::string name; ///< 模板名称
|
||||
std::string scenario; ///< 适用场景描述
|
||||
std::string content; ///< 模板内容(JSON/XML)
|
||||
std::string version; ///< 版本号
|
||||
std::chrono::system_clock::time_point effectiveTime; ///< 生效时间
|
||||
std::chrono::system_clock::time_point expireTime; ///< 过期时间
|
||||
std::chrono::system_clock::time_point createTime; ///< 创建时间
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 任务计划节点数据结构
|
||||
*
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 表示计划中的单个任务节点,支持树状结构。
|
||||
*/
|
||||
struct PlanNode {
|
||||
std::string nodeId; ///< 节点ID
|
||||
std::string planId; ///< 所属计划ID
|
||||
std::string parentNodeId; ///< 父节点ID(空为根节点)
|
||||
std::string taskType; ///< 任务类型
|
||||
std::string executeUnit; ///< 执行单位
|
||||
std::chrono::system_clock::time_point startTime; ///< 开始时间
|
||||
std::chrono::system_clock::time_point endTime; ///< 结束时间
|
||||
PlanStatus status = PlanStatus::DRAFT; ///< 节点状态
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 任务计划数据结构
|
||||
*
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 表示一个完整的作战任务计划,关联事件和模板,包含多个计划节点。
|
||||
*/
|
||||
struct TaskPlan {
|
||||
std::string id; ///< 计划ID
|
||||
std::string eventId; ///< 关联事件ID
|
||||
std::string templateId; ///< 使用的模板ID
|
||||
std::string responsiblePerson; ///< 负责人
|
||||
std::string remarks; ///< 备注
|
||||
PlanStatus status = PlanStatus::DRAFT; ///< 计划状态
|
||||
std::chrono::system_clock::time_point generateTime; ///< 生成时间
|
||||
std::vector<PlanNode> nodes; ///< 计划节点列表
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 分发日志数据结构
|
||||
*
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 记录每次任务分发操作的详细日志。
|
||||
*/
|
||||
struct DistributionLog {
|
||||
std::string logId; ///< 日志ID
|
||||
std::string planId; ///< 计划ID
|
||||
std::string targetAsset; ///< 目标资产标识
|
||||
std::chrono::system_clock::time_point sendTime; ///< 发送时间
|
||||
DistributionResponse response; ///< 响应状态
|
||||
int retryCount = 0; ///< 重发次数
|
||||
std::string errorCode; ///< 错误码
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 状态日志数据结构
|
||||
*
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 记录资产状态遥测数据的日志条目。
|
||||
*/
|
||||
struct StatusLog {
|
||||
std::string recordId; ///< 记录ID
|
||||
std::string assetId; ///< 资产ID
|
||||
std::chrono::system_clock::time_point timestamp; ///< 时间戳
|
||||
std::string statusCode; ///< 状态码
|
||||
std::string detailInfo; ///< 详细信息
|
||||
bool isAbnormal = false; ///< 是否异常
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 用户数据结构
|
||||
*
|
||||
* @requirement(name="人机交互界面", id="SU-03")
|
||||
* 表示系统用户信息,支持RBAC权限模型。
|
||||
*/
|
||||
struct User {
|
||||
std::string userId; ///< 用户ID
|
||||
std::string name; ///< 姓名
|
||||
std::string role; ///< 角色
|
||||
int permissionLevel = 0; ///< 权限等级
|
||||
std::string loginAccount; ///< 登录账号
|
||||
std::string contactInfo; ///< 联系方式
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 核心服务接口
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 事件接收与处理服务
|
||||
*
|
||||
* @requirement(name="事件接收与处理", id="SU-01")
|
||||
* @requirement(name="事件标准化处理", id="SU-02")
|
||||
* 负责接收原始事件、校验完整性、标准化并推送至内部消息队列。
|
||||
*/
|
||||
class EventService {
|
||||
public:
|
||||
EventService() = default;
|
||||
virtual ~EventService() = default;
|
||||
|
||||
/**
|
||||
* @requirement(name="事件接收与处理", id="SU-01")
|
||||
* 接收原始事件数据(JSON/XML格式),进行完整性校验。
|
||||
* @param rawData 原始事件数据字符串
|
||||
* @return true 接收成功,false 数据格式无效
|
||||
*/
|
||||
bool receiveEvent(const std::string& rawData);
|
||||
|
||||
/**
|
||||
* @requirement(name="事件接收与处理", id="SU-01")
|
||||
* 返回接收确认消息。
|
||||
* @param eventId 事件ID
|
||||
* @return 确认字符串
|
||||
*/
|
||||
std::string sendAck(const std::string& eventId);
|
||||
|
||||
/**
|
||||
* @requirement(name="事件标准化处理", id="SU-02")
|
||||
* 获取原始事件对象。
|
||||
* @param eventId 事件ID
|
||||
* @return 事件对象指针,未找到返回nullptr
|
||||
*/
|
||||
const Event* getRawEvent(const std::string& eventId) const;
|
||||
|
||||
/**
|
||||
* @requirement(name="事件标准化处理", id="SU-02")
|
||||
* 执行事件过滤、字段精简和时间戳坐标转换等标准化处理。
|
||||
* @param eventId 事件ID
|
||||
* @return true 处理成功,false 处理失败
|
||||
*/
|
||||
bool processEvent(const std::string& eventId);
|
||||
|
||||
/**
|
||||
* @requirement(name="事件标准化处理", id="SU-02")
|
||||
* 将标准化事件保存至内部存储。
|
||||
* @param event 标准化后的事件对象
|
||||
*/
|
||||
void saveStandardEvent(const Event& event);
|
||||
|
||||
/**
|
||||
* @requirement(name="事件展示与操作", id="SU-03")
|
||||
* 根据查询条件(时间范围、优先级、状态)查询事件列表。
|
||||
* @param filters 过滤条件映射
|
||||
* @return 匹配的事件列表
|
||||
*/
|
||||
std::vector<Event> queryEvents(const std::unordered_map<std::string, std::string>& filters) const;
|
||||
|
||||
/**
|
||||
* @requirement(name="事件展示与操作", id="SU-03")
|
||||
* 获取所有待处理事件。
|
||||
* @return 待处理事件列表
|
||||
*/
|
||||
std::vector<Event> getPendingEvents() const;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, Event> events_; ///< 内部事件存储
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 任务模板管理服务
|
||||
*
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 管理任务模板的接收、解析、版本比对、存储和推荐。
|
||||
*/
|
||||
class TemplateService {
|
||||
public:
|
||||
TemplateService() = default;
|
||||
virtual ~TemplateService() = default;
|
||||
|
||||
/**
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 接收并解析推送的任务模板集合。
|
||||
* @param rawData 原始模板数据(JSON/XML)
|
||||
* @return 成功解析的模板数量
|
||||
*/
|
||||
size_t receiveTemplates(const std::string& rawData);
|
||||
|
||||
/**
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 获取所有可用模板列表。
|
||||
* @return 模板列表
|
||||
*/
|
||||
std::vector<TaskTemplate> getTemplateList() const;
|
||||
|
||||
/**
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 用户手动选择指定模板。
|
||||
* @param templateId 模板ID
|
||||
* @return true 选择成功
|
||||
*/
|
||||
bool selectTemplate(const std::string& templateId);
|
||||
|
||||
/**
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 基于匹配算法自动推荐最优模板。
|
||||
* @param eventType 事件类型
|
||||
* @return 推荐的模板ID,无匹配返回空字符串
|
||||
*/
|
||||
std::string recommendTemplate(const std::string& eventType) const;
|
||||
|
||||
/**
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 获取配置参数映射。
|
||||
* @return 配置参数
|
||||
*/
|
||||
std::unordered_map<std::string, std::string> getConfig() const;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, TaskTemplate> templates_; ///< 模板存储
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 任务生成与计划管理服务
|
||||
*
|
||||
* @requirement(name="任务生成", id="SU-04")
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 处理从事件到任务计划的生成、计划列表管理、计划重配置和HITL通知。
|
||||
*/
|
||||
class PlanService {
|
||||
public:
|
||||
PlanService() = default;
|
||||
virtual ~PlanService() = default;
|
||||
|
||||
/**
|
||||
* @requirement(name="任务生成", id="SU-04")
|
||||
* 使用指定模板和用户输入参数,为待处理事件生成任务草案。
|
||||
* @param eventId 事件ID
|
||||
* @param templateId 模板ID
|
||||
* @param params 用户输入参数映射
|
||||
* @return 生成的任务计划ID,失败返回空字符串
|
||||
*/
|
||||
std::string generateTask(const std::string& eventId,
|
||||
const std::string& templateId,
|
||||
const std::unordered_map<std::string, std::string>& params);
|
||||
|
||||
/**
|
||||
* @requirement(name="任务生成", id="SU-04")
|
||||
* 提交任务草案。
|
||||
* @param planId 计划ID
|
||||
* @return 提交后的计划对象
|
||||
*/
|
||||
TaskPlan submitTask(const std::string& planId);
|
||||
|
||||
/**
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 获取所有计划的列表。
|
||||
* @return 计划列表
|
||||
*/
|
||||
std::vector<TaskPlan> getPlanList() const;
|
||||
|
||||
/**
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 基于权重设置对计划列表排序。
|
||||
* @param weights 排序权重映射
|
||||
*/
|
||||
void sortPlans(const std::unordered_map<std::string, int>& weights);
|
||||
|
||||
/**
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 提交计划重配置请求。
|
||||
* @param planId 计划ID
|
||||
* @param newNodes 新的节点列表
|
||||
* @return true 重配置成功
|
||||
*/
|
||||
bool reconfigurePlan(const std::string& planId, const std::vector<PlanNode>& newNodes);
|
||||
|
||||
/**
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 向指挥员发送人机协同(HITL)干预通知。
|
||||
* @param planId 计划ID
|
||||
* @param message 通知消息
|
||||
*/
|
||||
void notifyHITL(const std::string& planId, const std::string& message);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, TaskPlan> plans_; ///< 计划存储
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 方案分发服务
|
||||
*
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 负责将最终任务方案下发至作战资产,支持多种通信协议与ACK确认机制。
|
||||
*/
|
||||
class DistributionService {
|
||||
public:
|
||||
DistributionService() = default;
|
||||
virtual ~DistributionService() = default;
|
||||
|
||||
/**
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 启动分发流程,将计划分发至指定资产。
|
||||
* @param planId 计划ID
|
||||
* @return 分发日志列表
|
||||
*/
|
||||
std::vector<DistributionLog> distributePlan(const std::string& planId);
|
||||
|
||||
/**
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 接收资产返回的ACK/NACK响应。
|
||||
* @param logId 分发日志ID
|
||||
* @param response 响应状态
|
||||
* @return true 更新成功
|
||||
*/
|
||||
bool receiveAck(const std::string& logId, DistributionResponse response);
|
||||
|
||||
/**
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 更新UI分发状态指示灯。
|
||||
* @param planId 计划ID
|
||||
*/
|
||||
void updateStatus(const std::string& planId);
|
||||
|
||||
/**
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 查询指定计划的分发日志。
|
||||
* @param planId 计划ID
|
||||
* @return 分发日志列表
|
||||
*/
|
||||
std::vector<DistributionLog> getLogsByPlan(const std::string& planId) const;
|
||||
|
||||
private:
|
||||
std::vector<DistributionLog> logs_; ///< 分发日志存储
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 状态监控服务
|
||||
*
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 实时接收并解析资产遥测数据,监控执行状态,异常时触发报警。
|
||||
*/
|
||||
class StatusMonitorService {
|
||||
public:
|
||||
StatusMonitorService() = default;
|
||||
virtual ~StatusMonitorService() = default;
|
||||
|
||||
/**
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 接收二进制遥测数据。
|
||||
* @param rawData 原始遥测数据
|
||||
* @return 解析后的状态日志
|
||||
*/
|
||||
StatusLog receiveTelemetry(const std::vector<uint8_t>& rawData);
|
||||
|
||||
/**
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 解析遥测数据并提取状态信息。
|
||||
* @param rawData 原始二进制数据
|
||||
* @return 解析后的状态日志
|
||||
*/
|
||||
StatusLog parseData(const std::vector<uint8_t>& rawData);
|
||||
|
||||
/**
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 检测到异常时触发报警。
|
||||
* @param statusLog 异常状态日志
|
||||
* @return 报警消息
|
||||
*/
|
||||
std::string triggerAlarm(const StatusLog& statusLog);
|
||||
|
||||
/**
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 获取指定资产的最新状态。
|
||||
* @param assetId 资产ID
|
||||
* @return 最新状态日志
|
||||
*/
|
||||
StatusLog getLatestStatus(const std::string& assetId) const;
|
||||
|
||||
/**
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 检查并标记数据陈旧状态(超过阈值未更新)。
|
||||
* @param thresholdMs 阈值毫秒数
|
||||
*/
|
||||
void checkStaleData(uint64_t thresholdMs);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, StatusLog> latestStatus_; ///< 最新状态缓存
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 系统外观类
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 战场任务规划管理系统外观类
|
||||
*
|
||||
* @requirement(name="业务目标", id="REQ-BMP-001")
|
||||
* 提供统一入口,协调事件、模板、计划、分发、监控等子系统的交互。
|
||||
* 实现从战场事件感知到任务生成、执行监控的闭环管理。
|
||||
*/
|
||||
class BattlefieldMissionPlanner {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造系统外观类,初始化各子系统服务。
|
||||
*/
|
||||
BattlefieldMissionPlanner();
|
||||
|
||||
/**
|
||||
* @brief 初始化系统,加载配置。
|
||||
* @return true 初始化成功
|
||||
*/
|
||||
bool initialize();
|
||||
|
||||
/**
|
||||
* @brief 运行主循环,处理事件并驱动任务流程。
|
||||
*/
|
||||
void run();
|
||||
|
||||
/**
|
||||
* @brief 获取事件服务引用。
|
||||
*/
|
||||
EventService& getEventService() { return eventService_; }
|
||||
|
||||
/**
|
||||
* @brief 获取模板服务引用。
|
||||
*/
|
||||
TemplateService& getTemplateService() { return templateService_; }
|
||||
|
||||
/**
|
||||
* @brief 获取计划服务引用。
|
||||
*/
|
||||
PlanService& getPlanService() { return planService_; }
|
||||
|
||||
/**
|
||||
* @brief 获取分发服务引用。
|
||||
*/
|
||||
DistributionService& getDistributionService() { return distributionService_; }
|
||||
|
||||
/**
|
||||
* @brief 获取状态监控服务引用。
|
||||
*/
|
||||
StatusMonitorService& getStatusMonitorService() { return statusMonitorService_; }
|
||||
|
||||
private:
|
||||
EventService eventService_; ///< 事件接收与处理服务
|
||||
TemplateService templateService_; ///< 任务模板管理服务
|
||||
PlanService planService_; ///< 任务生成与计划管理服务
|
||||
DistributionService distributionService_; ///< 方案分发服务
|
||||
StatusMonitorService statusMonitorService_; ///< 状态监控服务
|
||||
};
|
||||
|
||||
} // namespace bmp
|
||||
|
||||
#endif // APP_HPP
|
||||
|
|
@ -0,0 +1,663 @@
|
|||
#include "app.hpp"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <ctime>
|
||||
|
||||
namespace bmp {
|
||||
|
||||
// ============================================================================
|
||||
// 辅助函数
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 生成唯一ID(基于时间戳和随机数)
|
||||
*/
|
||||
static std::string generateId() {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now.time_since_epoch()).count();
|
||||
std::mt19937 rng(static_cast<unsigned>(ms));
|
||||
std::uniform_int_distribution<int> dist(1000, 9999);
|
||||
std::ostringstream oss;
|
||||
oss << ms << "_" << dist(rng);
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前时间点
|
||||
*/
|
||||
static std::chrono::system_clock::time_point now() {
|
||||
return std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将时间点格式化为字符串
|
||||
*/
|
||||
static std::string timeToString(const std::chrono::system_clock::time_point& tp) {
|
||||
auto tt = std::chrono::system_clock::to_time_t(tp);
|
||||
std::tm tm;
|
||||
#if defined(_WIN32)
|
||||
localtime_s(&tm, &tt);
|
||||
#else
|
||||
localtime_r(&tt, &tm);
|
||||
#endif
|
||||
std::ostringstream oss;
|
||||
oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// EventService 实现
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @requirement(name="事件接收与处理", id="SU-01")
|
||||
* 接收原始事件数据,进行基本格式校验后存入内部存储。
|
||||
* 规则:非空检查、JSON/XML格式头识别,校验通过后创建事件对象。
|
||||
*/
|
||||
bool EventService::receiveEvent(const std::string& rawData) {
|
||||
if (rawData.empty()) {
|
||||
return false;
|
||||
}
|
||||
// 简单格式校验:检查是否以 { 或 < 开头
|
||||
if (rawData[0] != '{' && rawData[0] != '<') {
|
||||
return false;
|
||||
}
|
||||
Event evt;
|
||||
evt.id = generateId();
|
||||
evt.rawData = rawData;
|
||||
evt.status = EventStatus::PENDING;
|
||||
evt.priority = EventPriority::NORMAL;
|
||||
evt.occurTime = now();
|
||||
evt.createTime = now();
|
||||
evt.receiveNodeId = "NODE-001";
|
||||
evt.title = "未命名事件";
|
||||
evt.description = "从上游系统接收的原始事件";
|
||||
events_[evt.id] = evt;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="事件接收与处理", id="SU-01")
|
||||
* 生成确认消息,包含事件ID和时间戳。
|
||||
*/
|
||||
std::string EventService::sendAck(const std::string& eventId) {
|
||||
if (events_.count(eventId) == 0) {
|
||||
return "ACK:UNKNOWN";
|
||||
}
|
||||
return "ACK:" + eventId + "@" + timeToString(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="事件标准化处理", id="SU-02")
|
||||
* 根据事件ID获取原始事件对象指针。
|
||||
*/
|
||||
const Event* EventService::getRawEvent(const std::string& eventId) const {
|
||||
auto it = events_.find(eventId);
|
||||
if (it != events_.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="事件标准化处理", id="SU-02")
|
||||
* 执行事件标准化处理:
|
||||
* 1. 过滤无用字段,精简数据
|
||||
* 2. 统一时间戳格式
|
||||
* 3. 添加元数据(接收时间、处理节点ID)
|
||||
* 4. 标记状态为 PROCESSING
|
||||
*/
|
||||
bool EventService::processEvent(const std::string& eventId) {
|
||||
auto it = events_.find(eventId);
|
||||
if (it == events_.end()) {
|
||||
return false;
|
||||
}
|
||||
Event& evt = it->second;
|
||||
if (evt.status != EventStatus::PENDING) {
|
||||
return false;
|
||||
}
|
||||
// 模拟标准化处理:精简原始数据(保留前200字符)
|
||||
if (evt.rawData.size() > 200) {
|
||||
evt.rawData = evt.rawData.substr(0, 200) + "...(trimmed)";
|
||||
}
|
||||
evt.receiveNodeId = "NODE-001";
|
||||
evt.status = EventStatus::PROCESSING;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="事件标准化处理", id="SU-02")
|
||||
* 保存标准化事件到内部存储。如果事件已存在则覆盖。
|
||||
*/
|
||||
void EventService::saveStandardEvent(const Event& event) {
|
||||
events_[event.id] = event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="事件展示与操作", id="SU-03")
|
||||
* 根据过滤条件查询事件列表。
|
||||
* 支持按时间范围(time_from, time_to)、优先级(priority)、状态(status)过滤。
|
||||
*/
|
||||
std::vector<Event> EventService::queryEvents(
|
||||
const std::unordered_map<std::string, std::string>& filters) const
|
||||
{
|
||||
std::vector<Event> result;
|
||||
for (const auto& pair : events_) {
|
||||
const Event& evt = pair.second;
|
||||
bool match = true;
|
||||
auto it = filters.find("priority");
|
||||
if (it != filters.end()) {
|
||||
int prio = std::stoi(it->second);
|
||||
if (static_cast<int>(evt.priority) != prio) {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
it = filters.find("status");
|
||||
if (it != filters.end()) {
|
||||
if (it->second == "PENDING" && evt.status != EventStatus::PENDING) match = false;
|
||||
else if (it->second == "PROCESSING" && evt.status != EventStatus::PROCESSING) match = false;
|
||||
else if (it->second == "ACCEPTED" && evt.status != EventStatus::ACCEPTED) match = false;
|
||||
else if (it->second == "REJECTED" && evt.status != EventStatus::REJECTED) match = false;
|
||||
}
|
||||
if (match) {
|
||||
result.push_back(evt);
|
||||
}
|
||||
}
|
||||
// 按时间降序排列
|
||||
std::sort(result.begin(), result.end(),
|
||||
[](const Event& a, const Event& b) {
|
||||
return a.createTime > b.createTime;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="事件展示与操作", id="SU-03")
|
||||
* 获取所有状态为 PENDING 的待处理事件。
|
||||
*/
|
||||
std::vector<Event> EventService::getPendingEvents() const {
|
||||
std::vector<Event> result;
|
||||
for (const auto& pair : events_) {
|
||||
if (pair.second.status == EventStatus::PENDING) {
|
||||
result.push_back(pair.second);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TemplateService 实现
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 接收并解析模板集合。支持JSON数组或XML格式的批量模板。
|
||||
* 每个模板需包含 id, name, scenario, content, version 字段。
|
||||
*/
|
||||
size_t TemplateService::receiveTemplates(const std::string& rawData) {
|
||||
if (rawData.empty()) {
|
||||
return 0;
|
||||
}
|
||||
size_t count = 0;
|
||||
// 简易解析:按行分割,模拟从JSON/XML中提取模板
|
||||
std::istringstream stream(rawData);
|
||||
std::string line;
|
||||
TaskTemplate tmpl;
|
||||
bool inTemplate = false;
|
||||
while (std::getline(stream, line)) {
|
||||
if (line.find("\"id\"") != std::string::npos ||
|
||||
line.find("<id>") != std::string::npos) {
|
||||
auto pos = line.find(':');
|
||||
if (pos == std::string::npos) pos = line.find('>');
|
||||
if (pos != std::string::npos) {
|
||||
tmpl.id = line.substr(pos + 1);
|
||||
tmpl.id.erase(std::remove(tmpl.id.begin(), tmpl.id.end(), '\"'), tmpl.id.end());
|
||||
tmpl.id.erase(std::remove(tmpl.id.begin(), tmpl.id.end(), '>'), tmpl.id.end());
|
||||
tmpl.id.erase(std::remove(tmpl.id.begin(), tmpl.id.end(), '<'), tmpl.id.end());
|
||||
tmpl.id.erase(std::remove(tmpl.id.begin(), tmpl.id.end(), '/'), tmpl.id.end());
|
||||
tmpl.id.erase(std::remove(tmpl.id.begin(), tmpl.id.end(), ','), tmpl.id.end());
|
||||
tmpl.id.erase(std::remove(tmpl.id.begin(), tmpl.id.end(), ' '), tmpl.id.end());
|
||||
inTemplate = true;
|
||||
}
|
||||
}
|
||||
if (inTemplate && (line.find("\"name\"") != std::string::npos ||
|
||||
line.find("<name>") != std::string::npos)) {
|
||||
auto pos = line.find(':');
|
||||
if (pos == std::string::npos) pos = line.find('>');
|
||||
if (pos != std::string::npos) {
|
||||
tmpl.name = line.substr(pos + 1);
|
||||
tmpl.name.erase(std::remove(tmpl.name.begin(), tmpl.name.end(), '\"'), tmpl.name.end());
|
||||
tmpl.name.erase(std::remove(tmpl.name.begin(), tmpl.name.end(), '>'), tmpl.name.end());
|
||||
tmpl.name.erase(std::remove(tmpl.name.begin(), tmpl.name.end(), '<'), tmpl.name.end());
|
||||
tmpl.name.erase(std::remove(tmpl.name.begin(), tmpl.name.end(), '/'), tmpl.name.end());
|
||||
tmpl.name.erase(std::remove(tmpl.name.begin(), tmpl.name.end(), ','), tmpl.name.end());
|
||||
}
|
||||
}
|
||||
// 简单判断模板结束
|
||||
if (inTemplate && (line.find("}") != std::string::npos ||
|
||||
line.find("</template>") != std::string::npos)) {
|
||||
if (!tmpl.id.empty()) {
|
||||
if (tmpl.name.empty()) tmpl.name = "未命名模板";
|
||||
if (tmpl.scenario.empty()) tmpl.scenario = "通用场景";
|
||||
tmpl.version = "1.0";
|
||||
tmpl.createTime = now();
|
||||
tmpl.effectiveTime = now();
|
||||
tmpl.expireTime = now() + std::chrono::hours(24 * 365);
|
||||
templates_[tmpl.id] = tmpl;
|
||||
++count;
|
||||
}
|
||||
tmpl = TaskTemplate();
|
||||
inTemplate = false;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 返回所有已存储的模板列表。
|
||||
*/
|
||||
std::vector<TaskTemplate> TemplateService::getTemplateList() const {
|
||||
std::vector<TaskTemplate> result;
|
||||
result.reserve(templates_.size());
|
||||
for (const auto& pair : templates_) {
|
||||
result.push_back(pair.second);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 用户选择指定ID的模板。
|
||||
*/
|
||||
bool TemplateService::selectTemplate(const std::string& templateId) {
|
||||
return templates_.count(templateId) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 基于事件类型匹配推荐最优模板。
|
||||
* 匹配规则:模板的scenario字段包含事件类型关键字则推荐。
|
||||
*/
|
||||
std::string TemplateService::recommendTemplate(const std::string& eventType) const {
|
||||
if (templates_.empty()) {
|
||||
return "";
|
||||
}
|
||||
// 查找scenario字段包含事件类型关键字的模板
|
||||
for (const auto& pair : templates_) {
|
||||
if (pair.second.scenario.find(eventType) != std::string::npos) {
|
||||
return pair.second.id;
|
||||
}
|
||||
}
|
||||
// 无精确匹配,返回第一个模板
|
||||
return templates_.begin()->second.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 获取配置参数。
|
||||
*/
|
||||
std::unordered_map<std::string, std::string> TemplateService::getConfig() const {
|
||||
return {
|
||||
{"version_check", "enabled"},
|
||||
{"auto_recommend", "enabled"},
|
||||
{"max_templates", "1000"}
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// PlanService 实现
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @requirement(name="任务生成", id="SU-04")
|
||||
* 基于事件和模板生成任务草案。
|
||||
* 规则:
|
||||
* 1. 检查事件和模板是否存在
|
||||
* 2. 创建计划对象,生成唯一ID
|
||||
* 3. 创建默认计划节点(根节点)
|
||||
* 4. 保存计划为DRAFT状态
|
||||
* 5. 支持失败重试:如果计划已存在则返回空
|
||||
*/
|
||||
std::string PlanService::generateTask(
|
||||
const std::string& eventId,
|
||||
const std::string& templateId,
|
||||
const std::unordered_map<std::string, std::string>& params)
|
||||
{
|
||||
if (eventId.empty() || templateId.empty()) {
|
||||
return "";
|
||||
}
|
||||
// 生成唯一计划ID
|
||||
std::string planId = "PLAN_" + generateId();
|
||||
TaskPlan plan;
|
||||
plan.id = planId;
|
||||
plan.eventId = eventId;
|
||||
plan.templateId = templateId;
|
||||
plan.status = PlanStatus::DRAFT;
|
||||
plan.generateTime = now();
|
||||
plan.responsiblePerson = "系统自动生成";
|
||||
// 从参数中提取备注
|
||||
auto it = params.find("remarks");
|
||||
if (it != params.end()) {
|
||||
plan.remarks = it->second;
|
||||
}
|
||||
// 创建根节点
|
||||
PlanNode rootNode;
|
||||
rootNode.nodeId = "NODE_" + generateId();
|
||||
rootNode.planId = planId;
|
||||
rootNode.parentNodeId = "";
|
||||
rootNode.taskType = "主任务";
|
||||
rootNode.executeUnit = "联合作战指挥部";
|
||||
rootNode.startTime = now();
|
||||
rootNode.endTime = now() + std::chrono::hours(24);
|
||||
rootNode.status = PlanStatus::DRAFT;
|
||||
plan.nodes.push_back(rootNode);
|
||||
|
||||
plans_[planId] = plan;
|
||||
return planId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="任务生成", id="SU-04")
|
||||
* 提交任务草案,将状态从DRAFT更新为CONFIRMED。
|
||||
*/
|
||||
TaskPlan PlanService::submitTask(const std::string& planId) {
|
||||
TaskPlan emptyPlan;
|
||||
auto it = plans_.find(planId);
|
||||
if (it == plans_.end()) {
|
||||
return emptyPlan;
|
||||
}
|
||||
if (it->second.status == PlanStatus::DRAFT) {
|
||||
it->second.status = PlanStatus::CONFIRMED;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 获取所有计划列表。
|
||||
*/
|
||||
std::vector<TaskPlan> PlanService::getPlanList() const {
|
||||
std::vector<TaskPlan> result;
|
||||
result.reserve(plans_.size());
|
||||
for (const auto& pair : plans_) {
|
||||
result.push_back(pair.second);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 基于权重对计划排序。支持 priority(优先级权重)和 time(时间权重)。
|
||||
*/
|
||||
void PlanService::sortPlans(const std::unordered_map<std::string, int>& weights) {
|
||||
// 将计划转为向量
|
||||
std::vector<std::pair<std::string, TaskPlan>> items(plans_.begin(), plans_.end());
|
||||
// 根据权重排序
|
||||
int priorityWeight = 1;
|
||||
int timeWeight = 1;
|
||||
auto it = weights.find("priority");
|
||||
if (it != weights.end()) priorityWeight = it->second;
|
||||
it = weights.find("time");
|
||||
if (it != weights.end()) timeWeight = it->second;
|
||||
std::sort(items.begin(), items.end(),
|
||||
[priorityWeight, timeWeight](const auto& a, const auto& b) {
|
||||
// 按状态优先级和时间综合排序
|
||||
int scoreA = static_cast<int>(a.second.status) * priorityWeight;
|
||||
int scoreB = static_cast<int>(b.second.status) * priorityWeight;
|
||||
if (scoreA != scoreB) return scoreA > scoreB;
|
||||
if (timeWeight > 0) {
|
||||
return a.second.generateTime > b.second.generateTime;
|
||||
}
|
||||
return a.second.generateTime < b.second.generateTime;
|
||||
});
|
||||
// 重新构建map保持顺序(用unordered_map无法保持顺序,这里简化处理)
|
||||
// 实际工程中应使用有序容器,此处仅作演示
|
||||
std::unordered_map<std::string, TaskPlan> sortedPlans;
|
||||
for (const auto& item : items) {
|
||||
sortedPlans[item.first] = item.second;
|
||||
}
|
||||
plans_ = sortedPlans;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 计划重配置:替换计划的所有节点,并将状态重置为DRAFT。
|
||||
* 返回true表示重配置成功。
|
||||
*/
|
||||
bool PlanService::reconfigurePlan(const std::string& planId,
|
||||
const std::vector<PlanNode>& newNodes)
|
||||
{
|
||||
auto it = plans_.find(planId);
|
||||
if (it == plans_.end()) {
|
||||
return false;
|
||||
}
|
||||
it->second.nodes = newNodes;
|
||||
it->second.status = PlanStatus::DRAFT;
|
||||
it->second.generateTime = now();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 发送人机协同(HITL)干预通知。
|
||||
* 记录通知消息到计划备注中。
|
||||
*/
|
||||
void PlanService::notifyHITL(const std::string& planId, const std::string& message) {
|
||||
auto it = plans_.find(planId);
|
||||
if (it == plans_.end()) {
|
||||
return;
|
||||
}
|
||||
it->second.remarks += "\n[HITL通知@" + timeToString(now()) + "] " + message;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// DistributionService 实现
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 启动分发流程:为计划的每个节点创建分发日志,模拟发送过程。
|
||||
* 初始状态设为等待响应,retryCount为0。
|
||||
*/
|
||||
std::vector<DistributionLog> DistributionService::distributePlan(const std::string& planId) {
|
||||
std::vector<DistributionLog> result;
|
||||
// 为每个目标资产创建分发日志(简化:生成3条模拟记录)
|
||||
std::vector<std::string> assets = {"SATELLITE-01", "UAV-05", "RADAR-03"};
|
||||
for (const auto& asset : assets) {
|
||||
DistributionLog log;
|
||||
log.logId = "DLOG_" + generateId();
|
||||
log.planId = planId;
|
||||
log.targetAsset = asset;
|
||||
log.sendTime = now();
|
||||
log.response = DistributionResponse::TIMEOUT;
|
||||
log.retryCount = 0;
|
||||
log.errorCode = "";
|
||||
logs_.push_back(log);
|
||||
result.push_back(log);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 接收资产返回的确认响应。
|
||||
* 查找匹配的分发日志,更新响应状态。
|
||||
*/
|
||||
bool DistributionService::receiveAck(const std::string& logId, DistributionResponse response) {
|
||||
for (auto& log : logs_) {
|
||||
if (log.logId == logId) {
|
||||
log.response = response;
|
||||
if (response == DistributionResponse::NACK || response == DistributionResponse::TIMEOUT) {
|
||||
log.retryCount++;
|
||||
if (log.retryCount >= 3) {
|
||||
log.errorCode = "MAX_RETRY_EXCEEDED";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 更新UI状态指示。在实际系统中会触发前端渲染更新。
|
||||
*/
|
||||
void DistributionService::updateStatus(const std::string& planId) {
|
||||
// 在实际系统中,此方法会通过消息队列通知前端更新UI
|
||||
// 当前实现为占位
|
||||
(void)planId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 查询指定计划的所有分发日志。
|
||||
*/
|
||||
std::vector<DistributionLog> DistributionService::getLogsByPlan(const std::string& planId) const {
|
||||
std::vector<DistributionLog> result;
|
||||
for (const auto& log : logs_) {
|
||||
if (log.planId == planId) {
|
||||
result.push_back(log);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// StatusMonitorService 实现
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 接收遥测数据并解析。
|
||||
* 模拟从二进制数据中提取状态信息。
|
||||
*/
|
||||
StatusLog StatusMonitorService::receiveTelemetry(const std::vector<uint8_t>& rawData) {
|
||||
StatusLog log = parseData(rawData);
|
||||
latestStatus_[log.assetId] = log;
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 解析二进制遥测数据。
|
||||
* 格式假设:[4字节资产ID][8字节时间戳][2字节状态码][N字节详细信息]
|
||||
*/
|
||||
StatusLog StatusMonitorService::parseData(const std::vector<uint8_t>& rawData) {
|
||||
StatusLog log;
|
||||
log.recordId = "STATUS_" + generateId();
|
||||
log.timestamp = now();
|
||||
log.isAbnormal = false;
|
||||
if (rawData.size() < 14) {
|
||||
log.assetId = "UNKNOWN";
|
||||
log.statusCode = "ERR_INVALID_DATA";
|
||||
log.detailInfo = "数据长度不足";
|
||||
log.isAbnormal = true;
|
||||
return log;
|
||||
}
|
||||
// 模拟解析资产ID(前4字节转字符串)
|
||||
log.assetId = "AST_" + std::to_string((rawData[0] << 24) | (rawData[1] << 16) |
|
||||
(rawData[2] << 8) | rawData[3]);
|
||||
// 模拟解析状态码(第12-13字节)
|
||||
uint16_t statusCode = (rawData[12] << 8) | rawData[13];
|
||||
log.statusCode = std::to_string(statusCode);
|
||||
log.detailInfo = "遥测数据已解析";
|
||||
// 异常判断:状态码大于9000视为异常
|
||||
if (statusCode > 9000) {
|
||||
log.isAbnormal = true;
|
||||
log.detailInfo = "遥测异常:状态码 " + log.statusCode;
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 检测到异常状态时生成报警消息。
|
||||
*/
|
||||
std::string StatusMonitorService::triggerAlarm(const StatusLog& statusLog) {
|
||||
if (!statusLog.isAbnormal) {
|
||||
return "";
|
||||
}
|
||||
std::ostringstream oss;
|
||||
oss << "[ALARM] 资产 " << statusLog.assetId
|
||||
<< " 状态异常:" << statusLog.detailInfo
|
||||
<< " @ " << timeToString(statusLog.timestamp);
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 获取指定资产的最新状态日志。
|
||||
*/
|
||||
StatusLog StatusMonitorService::getLatestStatus(const std::string& assetId) const {
|
||||
StatusLog emptyLog;
|
||||
auto it = latestStatus_.find(assetId);
|
||||
if (it != latestStatus_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
emptyLog.assetId = assetId;
|
||||
emptyLog.statusCode = "NO_DATA";
|
||||
emptyLog.detailInfo = "无遥测数据";
|
||||
emptyLog.isAbnormal = true;
|
||||
return emptyLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 检查并标记数据陈旧。如果最新状态更新时间超过阈值,标记为STALE。
|
||||
*/
|
||||
void StatusMonitorService::checkStaleData(uint64_t thresholdMs) {
|
||||
auto nowTime = now();
|
||||
for (auto& pair : latestStatus_) {
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
nowTime - pair.second.timestamp).count();
|
||||
if (elapsed > static_cast<int64_t>(thresholdMs)) {
|
||||
pair.second.isAbnormal = true;
|
||||
pair.second.statusCode = "STALE";
|
||||
pair.second.detailInfo = "数据陈旧,最后更新于 " + timeToString(pair.second.timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// BattlefieldMissionPlanner 实现
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @requirement(name="业务目标", id="REQ-BMP-001")
|
||||
* 构造系统外观类,初始化各子系统服务实例。
|
||||
*/
|
||||
BattlefieldMissionPlanner::BattlefieldMissionPlanner()
|
||||
: eventService_()
|
||||
, templateService_()
|
||||
, planService_()
|
||||
, distributionService_()
|
||||
, statusMonitorService_()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="业务目标", id="REQ-BMP-001")
|
||||
* 初始化系统,加载配置。
|
||||
* 当前实现为占位,实际工程中会加载配置文件、连接数据库等。
|
||||
*/
|
||||
bool BattlefieldMissionPlanner::initialize() {
|
||||
// 实际工程中此处将加载配置文件、初始化数据库连接池、启动消息队列等
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @requirement(name="业务目标", id="REQ-BMP-001")
|
||||
* 运行主循环。
|
||||
* 当前实现为演示,输出系统启动信息。
|
||||
*/
|
||||
void BattlefieldMissionPlanner::run() {
|
||||
// 在实际系统中,此方法将启动事件监听循环、消息队列处理、定时任务等
|
||||
// 当前为占位实现
|
||||
}
|
||||
|
||||
} // namespace bmp
|
||||
|
|
@ -0,0 +1,347 @@
|
|||
/**
|
||||
* @file main.cpp
|
||||
* @brief 战场任务规划管理系统 - 命令行入口
|
||||
*
|
||||
* @requirement(name="业务目标", id="REQ-BMP-001")
|
||||
* 提供命令行交互接口,演示从事件接收、模板管理、任务生成到方案分发、状态监控的完整闭环流程。
|
||||
*/
|
||||
|
||||
#include "app.hpp"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
using namespace bmp;
|
||||
|
||||
/**
|
||||
* @brief 打印事件信息
|
||||
*/
|
||||
static void printEvent(const Event& evt) {
|
||||
std::cout << " [事件] ID: " << evt.id
|
||||
<< " | 标题: " << evt.title
|
||||
<< " | 优先级: " << static_cast<int>(evt.priority)
|
||||
<< " | 状态: ";
|
||||
switch (evt.status) {
|
||||
case EventStatus::PENDING: std::cout << "待处理"; break;
|
||||
case EventStatus::PROCESSING: std::cout << "处理中"; break;
|
||||
case EventStatus::ACCEPTED: std::cout << "已接受"; break;
|
||||
case EventStatus::REJECTED: std::cout << "已拒绝"; break;
|
||||
case EventStatus::ERROR: std::cout << "异常"; break;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 打印模板信息
|
||||
*/
|
||||
static void printTemplate(const TaskTemplate& tmpl) {
|
||||
std::cout << " [模板] ID: " << tmpl.id
|
||||
<< " | 名称: " << tmpl.name
|
||||
<< " | 场景: " << tmpl.scenario
|
||||
<< " | 版本: " << tmpl.version << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 打印计划信息
|
||||
*/
|
||||
static void printPlan(const TaskPlan& plan) {
|
||||
std::cout << " [计划] ID: " << plan.id
|
||||
<< " | 事件: " << plan.eventId
|
||||
<< " | 模板: " << plan.templateId
|
||||
<< " | 状态: ";
|
||||
switch (plan.status) {
|
||||
case PlanStatus::DRAFT: std::cout << "草稿"; break;
|
||||
case PlanStatus::CONFIRMED: std::cout << "已确认"; break;
|
||||
case PlanStatus::DISTRIBUTING: std::cout << "分发中"; break;
|
||||
case PlanStatus::EXECUTING: std::cout << "执行中"; break;
|
||||
case PlanStatus::COMPLETED: std::cout << "已完成"; break;
|
||||
case PlanStatus::FAILED: std::cout << "失败"; break;
|
||||
case PlanStatus::CANCELLED: std::cout << "已取消"; break;
|
||||
}
|
||||
std::cout << " | 节点数: " << plan.nodes.size() << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 打印分发日志
|
||||
*/
|
||||
static void printDistributionLog(const DistributionLog& log) {
|
||||
std::cout << " [分发] 日志ID: " << log.logId
|
||||
<< " | 目标: " << log.targetAsset
|
||||
<< " | 重试: " << log.retryCount
|
||||
<< " | 响应: ";
|
||||
switch (log.response) {
|
||||
case DistributionResponse::ACK: std::cout << "确认"; break;
|
||||
case DistributionResponse::NACK: std::cout << "否定"; break;
|
||||
case DistributionResponse::TIMEOUT: std::cout << "超时"; break;
|
||||
case DistributionResponse::ERROR: std::cout << "错误"; break;
|
||||
}
|
||||
std::cout << " | 错误码: " << log.errorCode << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 打印状态日志
|
||||
*/
|
||||
static void printStatusLog(const StatusLog& log) {
|
||||
std::cout << " [状态] 资产: " << log.assetId
|
||||
<< " | 状态码: " << log.statusCode
|
||||
<< " | 异常: " << (log.isAbnormal ? "是" : "否")
|
||||
<< " | 详情: " << log.detailInfo << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 分隔线
|
||||
*/
|
||||
static void separator() {
|
||||
std::cout << "----------------------------------------" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 主函数
|
||||
*
|
||||
* 演示完整的业务流程:
|
||||
* 1. 初始化系统
|
||||
* 2. 接收事件并标准化
|
||||
* 3. 加载模板并推荐
|
||||
* 4. 生成任务计划
|
||||
* 5. 分发方案
|
||||
* 6. 监控状态
|
||||
*/
|
||||
int main() {
|
||||
std::cout << "========================================" << std::endl;
|
||||
std::cout << " 战场任务规划管理系统 (BMP) v1.0" << std::endl;
|
||||
std::cout << "========================================" << std::endl;
|
||||
|
||||
// 初始化系统
|
||||
BattlefieldMissionPlanner bmp;
|
||||
if (!bmp.initialize()) {
|
||||
std::cerr << "系统初始化失败!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << "系统初始化成功。" << std::endl << std::endl;
|
||||
|
||||
// ============================================================
|
||||
// 1. 事件接收与处理
|
||||
// ============================================================
|
||||
std::cout << "=== 1. 事件接收与处理 ===" << std::endl;
|
||||
|
||||
// 模拟接收JSON格式事件
|
||||
std::string eventJson1 = "{ \"type\": \"敌情侦察\", \"priority\": \"HIGH\", "
|
||||
"\"location\": { \"lat\": 39.9, \"lon\": 116.4 }, "
|
||||
"\"description\": \"发现敌方装甲集群正向北移动\" }";
|
||||
bool ok = bmp.getEventService().receiveEvent(eventJson1);
|
||||
std::cout << "接收事件1: " << (ok ? "成功" : "失败") << std::endl;
|
||||
|
||||
// 模拟接收XML格式事件
|
||||
std::string eventXml2 = "<event><type>空情预警</type><priority>CRITICAL</priority>"
|
||||
"<location><lat>31.2</lat><lon>121.5</lon></location>"
|
||||
"<description>探测到不明飞行物接近领空</description></event>";
|
||||
ok = bmp.getEventService().receiveEvent(eventXml2);
|
||||
std::cout << "接收事件2: " << (ok ? "成功" : "失败") << std::endl;
|
||||
|
||||
// 模拟事件3(用于拒绝场景)
|
||||
std::string eventJson3 = "{ \"type\": \"后勤补给\", \"priority\": \"NORMAL\", "
|
||||
"\"description\": \"弹药库存低于阈值,需紧急补给\" }";
|
||||
ok = bmp.getEventService().receiveEvent(eventJson3);
|
||||
std::cout << "接收事件3: " << (ok ? "成功" : "失败") << std::endl;
|
||||
|
||||
separator();
|
||||
|
||||
// 查询待处理事件
|
||||
auto pendingEvents = bmp.getEventService().getPendingEvents();
|
||||
std::cout << "待处理事件数量: " << pendingEvents.size() << std::endl;
|
||||
for (const auto& evt : pendingEvents) {
|
||||
printEvent(evt);
|
||||
}
|
||||
|
||||
separator();
|
||||
|
||||
// 标准化处理事件1
|
||||
std::cout << "标准化处理事件1..." << std::endl;
|
||||
if (!pendingEvents.empty()) {
|
||||
bmp.getEventService().processEvent(pendingEvents[0].id);
|
||||
}
|
||||
|
||||
// 查询所有事件
|
||||
std::cout << "所有事件列表:" << std::endl;
|
||||
auto allEvents = bmp.getEventService().queryEvents({});
|
||||
for (const auto& evt : allEvents) {
|
||||
printEvent(evt);
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
// ============================================================
|
||||
// 2. 任务模板管理
|
||||
// ============================================================
|
||||
std::cout << "=== 2. 任务模板管理 ===" << std::endl;
|
||||
std::string templateData =
|
||||
"{\"id\":\"TMPL-A1\",\"name\":\"敌情侦察模板\",\"scenario\":\"敌情侦察\"}\n"
|
||||
"{\"id\":\"TMPL-B2\",\"name\":\"空情预警模板\",\"scenario\":\"空情预警\"}\n"
|
||||
"{\"id\":\"TMPL-C3\",\"name\":\"后勤补给模板\",\"scenario\":\"后勤补给\"}";
|
||||
|
||||
size_t templateCount = bmp.getTemplateService().receiveTemplates(templateData);
|
||||
std::cout << "加载模板数量: " << templateCount << std::endl;
|
||||
|
||||
auto templates = bmp.getTemplateService().getTemplateList();
|
||||
for (const auto& tmpl : templates) {
|
||||
printTemplate(tmpl);
|
||||
}
|
||||
|
||||
// 自动推荐模板
|
||||
std::string recommended = bmp.getTemplateService().recommendTemplate("敌情侦察");
|
||||
std::cout << "为'敌情侦察'推荐模板: " << (recommended.empty() ? "无推荐" : recommended) << std::endl;
|
||||
|
||||
recommended = bmp.getTemplateService().recommendTemplate("空情预警");
|
||||
std::cout << "为'空情预警'推荐模板: " << (recommended.empty() ? "无推荐" : recommended) << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
// ============================================================
|
||||
// 3. 任务生成与计划管理
|
||||
// ============================================================
|
||||
std::cout << "=== 3. 任务生成与计划管理 ===" << std::endl;
|
||||
|
||||
// 基于事件1和推荐模板生成任务
|
||||
std::string generatedPlanId = bmp.getPlanService().generateTask(
|
||||
pendingEvents[0].id, "TMPL-A1",
|
||||
{{"remarks", "优先处理,需快速响应"}});
|
||||
std::cout << "生成任务计划: " << (generatedPlanId.empty() ? "失败" : generatedPlanId) << std::endl;
|
||||
|
||||
if (!generatedPlanId.empty()) {
|
||||
// 提交计划
|
||||
auto submittedPlan = bmp.getPlanService().submitTask(generatedPlanId);
|
||||
std::cout << "提交计划后状态: ";
|
||||
printPlan(submittedPlan);
|
||||
|
||||
// 计划重配置
|
||||
std::cout << "执行计划重配置..." << std::endl;
|
||||
std::vector<PlanNode> newNodes;
|
||||
PlanNode node1;
|
||||
node1.nodeId = "NODE_NEW_001";
|
||||
node1.planId = generatedPlanId;
|
||||
node1.taskType = "侦察";
|
||||
node1.executeUnit = "无人侦察机编队";
|
||||
node1.startTime = std::chrono::system_clock::now();
|
||||
node1.endTime = std::chrono::system_clock::now() + std::chrono::hours(6);
|
||||
node1.status = PlanStatus::DRAFT;
|
||||
newNodes.push_back(node1);
|
||||
PlanNode node2;
|
||||
node2.nodeId = "NODE_NEW_002";
|
||||
node2.planId = generatedPlanId;
|
||||
node2.parentNodeId = "NODE_NEW_001";
|
||||
node2.taskType = "目标确认";
|
||||
node2.executeUnit = "情报分析中心";
|
||||
node2.startTime = std::chrono::system_clock::now() + std::chrono::hours(6);
|
||||
node2.endTime = std::chrono::system_clock::now() + std::chrono::hours(8);
|
||||
node2.status = PlanStatus::DRAFT;
|
||||
newNodes.push_back(node2);
|
||||
bool reconfigured = bmp.getPlanService().reconfigurePlan(generatedPlanId, newNodes);
|
||||
std::cout << "重配置: " << (reconfigured ? "成功" : "失败") << std::endl;
|
||||
|
||||
// HITL通知
|
||||
bmp.getPlanService().notifyHITL(generatedPlanId, "请确认新侦察方案");
|
||||
std::cout << "已发送HITL通知给指挥员。" << std::endl;
|
||||
}
|
||||
|
||||
// 查看所有计划
|
||||
std::cout << "当前计划列表:" << std::endl;
|
||||
auto planList = bmp.getPlanService().getPlanList();
|
||||
for (const auto& plan : planList) {
|
||||
printPlan(plan);
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
// ============================================================
|
||||
// 4. 方案分发
|
||||
// ============================================================
|
||||
std::cout << "=== 4. 方案分发 ===" << std::endl;
|
||||
if (!generatedPlanId.empty()) {
|
||||
auto distLogs = bmp.getDistributionService().distributePlan(generatedPlanId);
|
||||
std::cout << "分发日志数量: " << distLogs.size() << std::endl;
|
||||
for (const auto& log : distLogs) {
|
||||
printDistributionLog(log);
|
||||
}
|
||||
|
||||
// 模拟接收ACK
|
||||
if (!distLogs.empty()) {
|
||||
bool ackOk = bmp.getDistributionService().receiveAck(
|
||||
distLogs[0].logId, DistributionResponse::ACK);
|
||||
std::cout << "接收资产确认: " << (ackOk ? "成功" : "失败") << std::endl;
|
||||
|
||||
// 模拟接收NACK
|
||||
if (distLogs.size() > 1) {
|
||||
bmp.getDistributionService().receiveAck(
|
||||
distLogs[1].logId, DistributionResponse::NACK);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "更新后分发日志:" << std::endl;
|
||||
auto updatedLogs = bmp.getDistributionService().getLogsByPlan(generatedPlanId);
|
||||
for (const auto& log : updatedLogs) {
|
||||
printDistributionLog(log);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
// ============================================================
|
||||
// 5. 状态监控
|
||||
// ============================================================
|
||||
std::cout << "=== 5. 状态监控 ===" << std::endl;
|
||||
|
||||
// 模拟遥测数据(二进制格式)
|
||||
std::vector<uint8_t> telemetry1 = {
|
||||
0x00, 0x01, 0x00, 0x01, // 资产ID: AST_65537
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 时间戳占位
|
||||
0x23, 0x28, // 状态码: 9000 (正常)
|
||||
0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C // "Normal"
|
||||
};
|
||||
auto statusLog1 = bmp.getStatusMonitorService().receiveTelemetry(telemetry1);
|
||||
std::cout << "接收遥测数据1:" << std::endl;
|
||||
printStatusLog(statusLog1);
|
||||
|
||||
// 模拟异常遥测数据
|
||||
std::vector<uint8_t> telemetry2 = {
|
||||
0x00, 0x01, 0x00, 0x02, // 资产ID: AST_65538
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x23, 0x38, // 状态码: 9016 (异常)
|
||||
0x45, 0x72, 0x72, 0x6F, 0x72 // "Error"
|
||||
};
|
||||
auto statusLog2 = bmp.getStatusMonitorService().receiveTelemetry(telemetry2);
|
||||
std::cout << "接收遥测数据2:" << std::endl;
|
||||
printStatusLog(statusLog2);
|
||||
|
||||
// 触发报警
|
||||
if (statusLog2.isAbnormal) {
|
||||
std::string alarm = bmp.getStatusMonitorService().triggerAlarm(statusLog2);
|
||||
std::cout << "报警信息: " << alarm << std::endl;
|
||||
}
|
||||
|
||||
// 检查数据陈旧
|
||||
std::cout << "检查数据陈旧(阈值100ms)..." << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(150));
|
||||
bmp.getStatusMonitorService().checkStaleData(100);
|
||||
auto staleStatus = bmp.getStatusMonitorService().getLatestStatus("AST_65537");
|
||||
std::cout << "资产 AST_65537 最新状态:" << std::endl;
|
||||
printStatusLog(staleStatus);
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
// ============================================================
|
||||
// 6. 系统运行
|
||||
// ============================================================
|
||||
std::cout << "=== 6. 系统运行 ===" << std::endl;
|
||||
bmp.run();
|
||||
std::cout << "系统主循环启动完成(演示模式)。" << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "========================================" << std::endl;
|
||||
std::cout << " 系统演示结束" << std::endl;
|
||||
std::cout << "========================================" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,391 @@
|
|||
/**
|
||||
* @file basic_test.cpp
|
||||
* @brief 战场任务规划管理系统基本单元测试
|
||||
*
|
||||
* 使用标准库 assert 进行单元测试,覆盖核心功能模块:
|
||||
* - SU-01: 事件接收与处理
|
||||
* - SU-02: 事件标准化处理
|
||||
* - SU-03: 事件展示与操作
|
||||
* - SU-04: 任务生成
|
||||
* - SU-05: 任务模板管理
|
||||
* - SU-06: 计划管理
|
||||
* - SU-07: 方案分发
|
||||
* - SU-08: 状态监控
|
||||
*/
|
||||
|
||||
#include "app.hpp"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
using namespace bmp;
|
||||
|
||||
/**
|
||||
* @brief 测试事件接收与处理(SU-01)
|
||||
*
|
||||
* @requirement(name="事件接收与处理", id="SU-01")
|
||||
* 测试接收有效JSON事件、有效XML事件、空数据和无效数据。
|
||||
*/
|
||||
static void testEventReception() {
|
||||
std::cout << "[测试] SU-01: 事件接收与处理" << std::endl;
|
||||
EventService svc;
|
||||
|
||||
// 测试1: 接收有效JSON事件
|
||||
std::string jsonEvent = "{ \"type\": \"敌情侦察\", \"priority\": \"HIGH\" }";
|
||||
bool result = svc.receiveEvent(jsonEvent);
|
||||
assert(result && "接收有效JSON事件应该成功");
|
||||
|
||||
// 测试2: 接收有效XML事件
|
||||
std::string xmlEvent = "<event><type>空情预警</type></event>";
|
||||
result = svc.receiveEvent(xmlEvent);
|
||||
assert(result && "接收有效XML事件应该成功");
|
||||
|
||||
// 测试3: 接收空数据
|
||||
result = svc.receiveEvent("");
|
||||
assert(!result && "接收空数据应该失败");
|
||||
|
||||
// 测试4: 接收无效数据(既不是JSON也不是XML)
|
||||
result = svc.receiveEvent("invalid data without brackets");
|
||||
assert(!result && "接收无效格式数据应该失败");
|
||||
|
||||
// 测试5: 发送ACK
|
||||
std::string ack = svc.sendAck("unknown");
|
||||
assert(ack == "ACK:UNKNOWN" && "未知事件ID应返回 UNKNOWN");
|
||||
|
||||
std::cout << " SU-01 测试通过!" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试事件标准化处理(SU-02)
|
||||
*
|
||||
* @requirement(name="事件标准化处理", id="SU-02")
|
||||
* 测试获取原始事件、处理事件和保存标准化事件。
|
||||
*/
|
||||
static void testEventStandardization() {
|
||||
std::cout << "[测试] SU-02: 事件标准化处理" << std::endl;
|
||||
EventService svc;
|
||||
|
||||
// 准备测试数据
|
||||
std::string jsonEvent = "{ \"type\": \"敌情侦察\", \"priority\": \"HIGH\" }";
|
||||
svc.receiveEvent(jsonEvent);
|
||||
auto pending = svc.getPendingEvents();
|
||||
assert(!pending.empty() && "应有待处理事件");
|
||||
|
||||
// 测试1: 获取原始事件
|
||||
const Event* raw = svc.getRawEvent(pending[0].id);
|
||||
assert(raw != nullptr && "应能获取原始事件");
|
||||
assert(raw->status == EventStatus::PENDING && "原始事件状态应为PENDING");
|
||||
|
||||
// 测试2: 处理事件(标准化)
|
||||
bool processed = svc.processEvent(pending[0].id);
|
||||
assert(processed && "事件标准化应成功");
|
||||
|
||||
// 测试3: 再次处理应失败(状态已变更)
|
||||
processed = svc.processEvent(pending[0].id);
|
||||
assert(!processed && "重复处理应失败");
|
||||
|
||||
// 测试4: 处理不存在的事件
|
||||
processed = svc.processEvent("nonexistent");
|
||||
assert(!processed && "处理不存在的事件应失败");
|
||||
|
||||
// 测试5: 保存标准化事件
|
||||
Event customEvent;
|
||||
customEvent.id = "CUSTOM_001";
|
||||
customEvent.title = "测试事件";
|
||||
customEvent.status = EventStatus::ACCEPTED;
|
||||
svc.saveStandardEvent(customEvent);
|
||||
const Event* saved = svc.getRawEvent("CUSTOM_001");
|
||||
assert(saved != nullptr && "保存后应能获取标准化事件");
|
||||
assert(saved->status == EventStatus::ACCEPTED && "标准化事件状态应正确");
|
||||
|
||||
std::cout << " SU-02 测试通过!" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试事件展示与操作(SU-03)
|
||||
*
|
||||
* @requirement(name="事件展示与操作", id="SU-03")
|
||||
* 测试事件查询、获取待处理事件等功能。
|
||||
*/
|
||||
static void testEventQuery() {
|
||||
std::cout << "[测试] SU-03: 事件展示与操作" << std::endl;
|
||||
EventService svc;
|
||||
|
||||
// 准备测试数据
|
||||
svc.receiveEvent("{ \"type\": \"A\" }");
|
||||
svc.receiveEvent("{ \"type\": \"B\" }");
|
||||
|
||||
// 测试1: 查询所有事件
|
||||
auto all = svc.queryEvents({});
|
||||
assert(all.size() == 2 && "应有2个事件");
|
||||
|
||||
// 测试2: 获取待处理事件
|
||||
auto pending = svc.getPendingEvents();
|
||||
assert(pending.size() == 2 && "应有2个待处理事件");
|
||||
|
||||
// 测试3: 过滤状态
|
||||
auto filtered = svc.queryEvents({{"status", "PENDING"}});
|
||||
assert(filtered.size() == 2 && "过滤PENDING应有2个");
|
||||
|
||||
std::cout << " SU-03 测试通过!" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试任务模板管理(SU-05)
|
||||
*
|
||||
* @requirement(name="任务模板管理", id="SU-05")
|
||||
* 测试模板接收、列表、选择和推荐功能。
|
||||
*/
|
||||
static void testTemplateManagement() {
|
||||
std::cout << "[测试] SU-05: 任务模板管理" << std::endl;
|
||||
TemplateService svc;
|
||||
|
||||
// 测试1: 接收空数据
|
||||
size_t count = svc.receiveTemplates("");
|
||||
assert(count == 0 && "空数据应解析出0个模板");
|
||||
|
||||
// 测试2: 接收有效模板
|
||||
std::string tmplData =
|
||||
"{\"id\":\"T1\",\"name\":\"模板1\",\"scenario\":\"侦察\"}\n"
|
||||
"{\"id\":\"T2\",\"name\":\"模板2\",\"scenario\":\"预警\"}\n";
|
||||
count = svc.receiveTemplates(tmplData);
|
||||
assert(count == 2 && "应有2个模板被解析");
|
||||
|
||||
// 测试3: 获取模板列表
|
||||
auto list = svc.getTemplateList();
|
||||
assert(list.size() == 2 && "模板列表应有2个");
|
||||
|
||||
// 测试4: 选择模板
|
||||
bool selected = svc.selectTemplate("T1");
|
||||
assert(selected && "选择存在的模板应成功");
|
||||
|
||||
selected = svc.selectTemplate("NONEXIST");
|
||||
assert(!selected && "选择不存在的模板应失败");
|
||||
|
||||
// 测试5: 推荐模板
|
||||
std::string recommended = svc.recommendTemplate("侦察");
|
||||
assert(recommended == "T1" && "应为侦察推荐T1模板");
|
||||
|
||||
recommended = svc.recommendTemplate("未知");
|
||||
assert(!recommended.empty() && "无匹配时应有默认推荐");
|
||||
|
||||
// 测试6: 获取配置
|
||||
auto config = svc.getConfig();
|
||||
assert(config.find("auto_recommend") != config.end() && "应有auto_recommend配置");
|
||||
|
||||
std::cout << " SU-05 测试通过!" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试任务生成与计划管理(SU-04, SU-06)
|
||||
*
|
||||
* @requirement(name="任务生成", id="SU-04")
|
||||
* @requirement(name="计划管理", id="SU-06")
|
||||
* 测试任务生成、提交、计划列表、排序、重配置和HITL通知。
|
||||
*/
|
||||
static void testPlanManagement() {
|
||||
std::cout << "[测试] SU-04/SU-06: 任务生成与计划管理" << std::endl;
|
||||
PlanService svc;
|
||||
|
||||
// 测试1: 生成任务 - 空参数应失败
|
||||
std::string planId = svc.generateTask("", "T1", {});
|
||||
assert(planId.empty() && "空事件ID应生成失败");
|
||||
|
||||
// 测试2: 生成任务 - 有效参数
|
||||
planId = svc.generateTask("EVT_001", "T1", {{"remarks", "测试"}});
|
||||
assert(!planId.empty() && "有效参数应生成计划");
|
||||
assert(planId.find("PLAN_") == 0 && "计划ID应以PLAN_开头");
|
||||
|
||||
// 测试3: 提交任务
|
||||
TaskPlan plan = svc.submitTask(planId);
|
||||
assert(plan.status == PlanStatus::CONFIRMED && "提交后状态应为CONFIRMED");
|
||||
assert(plan.id == planId && "返回的计划ID应匹配");
|
||||
|
||||
// 测试4: 提交不存在的计划
|
||||
TaskPlan emptyPlan = svc.submitTask("NONEXIST");
|
||||
assert(emptyPlan.id.empty() && "不存在的计划应返回空");
|
||||
|
||||
// 测试5: 获取计划列表
|
||||
auto plans = svc.getPlanList();
|
||||
assert(plans.size() == 1 && "应有1个计划");
|
||||
|
||||
// 测试6: 排序计划
|
||||
svc.sortPlans({{"priority", 1}, {"time", 1}});
|
||||
|
||||
// 测试7: 计划重配置
|
||||
std::vector<PlanNode> newNodes;
|
||||
PlanNode node;
|
||||
node.nodeId = "NODE_001";
|
||||
node.planId = planId;
|
||||
node.taskType = "侦察";
|
||||
node.executeUnit = "无人机";
|
||||
newNodes.push_back(node);
|
||||
bool reconfigured = svc.reconfigurePlan(planId, newNodes);
|
||||
assert(reconfigured && "重配置应成功");
|
||||
|
||||
// 重配置不存在的计划
|
||||
reconfigured = svc.reconfigurePlan("NONEXIST", newNodes);
|
||||
assert(!reconfigured && "重配置不存在计划应失败");
|
||||
|
||||
// 测试8: HITL通知
|
||||
svc.notifyHITL(planId, "请确认方案");
|
||||
svc.notifyHITL("NONEXIST", "测试"); // 不应崩溃
|
||||
|
||||
std::cout << " SU-04/SU-06 测试通过!" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试方案分发(SU-07)
|
||||
*
|
||||
* @requirement(name="方案分发", id="SU-07")
|
||||
* 测试分发流程、ACK接收、重试和状态更新。
|
||||
*/
|
||||
static void testDistribution() {
|
||||
std::cout << "[测试] SU-07: 方案分发" << std::endl;
|
||||
DistributionService svc;
|
||||
|
||||
// 测试1: 分发计划
|
||||
auto logs = svc.distributePlan("PLAN_001");
|
||||
assert(logs.size() == 3 && "应有3条分发日志");
|
||||
for (const auto& log : logs) {
|
||||
assert(!log.logId.empty() && "日志ID不应为空");
|
||||
assert(log.response == DistributionResponse::TIMEOUT && "初始状态应为TIMEOUT");
|
||||
assert(log.retryCount == 0 && "初始重试次数应为0");
|
||||
}
|
||||
|
||||
// 测试2: 接收ACK
|
||||
bool ackOk = svc.receiveAck(logs[0].logId, DistributionResponse::ACK);
|
||||
assert(ackOk && "接收ACK应成功");
|
||||
|
||||
ackOk = svc.receiveAck("NONEXIST", DistributionResponse::ACK);
|
||||
assert(!ackOk && "接收不存在的日志ACK应失败");
|
||||
|
||||
// 测试3: 接收NACK并验证重试
|
||||
bool nackOk = svc.receiveAck(logs[1].logId, DistributionResponse::NACK);
|
||||
assert(nackOk && "接收NACK应成功");
|
||||
|
||||
// 测试4: 查询分发日志
|
||||
auto queriedLogs = svc.getLogsByPlan("PLAN_001");
|
||||
assert(queriedLogs.size() == 3 && "应有3条日志");
|
||||
assert(queriedLogs[0].response == DistributionResponse::ACK && "第一条应为ACK");
|
||||
assert(queriedLogs[1].response == DistributionResponse::NACK && "第二条应为NACK");
|
||||
|
||||
// 测试5: 状态更新(不崩溃即可)
|
||||
svc.updateStatus("PLAN_001");
|
||||
|
||||
std::cout << " SU-07 测试通过!" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试状态监控(SU-08)
|
||||
*
|
||||
* @requirement(name="状态监控", id="SU-08")
|
||||
* 测试遥测数据接收、解析、报警触发和数据陈旧检查。
|
||||
*/
|
||||
static void testStatusMonitoring() {
|
||||
std::cout << "[测试] SU-08: 状态监控" << std::endl;
|
||||
StatusMonitorService svc;
|
||||
|
||||
// 测试1: 接收有效遥测数据
|
||||
std::vector<uint8_t> validData = {
|
||||
0x00, 0x01, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x23, 0x28,
|
||||
0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C
|
||||
};
|
||||
StatusLog log = svc.receiveTelemetry(validData);
|
||||
assert(!log.recordId.empty() && "记录ID不应为空");
|
||||
assert(!log.isAbnormal && "正常状态码不应标记为异常");
|
||||
|
||||
// 测试2: 接收异常遥测数据
|
||||
std::vector<uint8_t> abnormalData = {
|
||||
0x00, 0x01, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x23, 0x38, // 9016 > 9000
|
||||
0x45, 0x72, 0x72, 0x6F, 0x72
|
||||
};
|
||||
StatusLog abnormalLog = svc.receiveTelemetry(abnormalData);
|
||||
assert(abnormalLog.isAbnormal && "状态码大于9000应标记为异常");
|
||||
|
||||
// 测试3: 接收短数据(无效)
|
||||
std::vector<uint8_t> shortData = {0x00, 0x01};
|
||||
StatusLog shortLog = svc.receiveTelemetry(shortData);
|
||||
assert(shortLog.isAbnormal && "短数据应标记为异常");
|
||||
assert(shortLog.statusCode == "ERR_INVALID_DATA" && "短数据应有错误码");
|
||||
|
||||
// 测试4: 触发报警
|
||||
std::string alarm = svc.triggerAlarm(abnormalLog);
|
||||
assert(!alarm.empty() && "异常状态应触发报警");
|
||||
assert(alarm.find("[ALARM]") == 0 && "报警消息应以[ALARM]开头");
|
||||
|
||||
// 正常状态不触发报警
|
||||
alarm = svc.triggerAlarm(log);
|
||||
assert(alarm.empty() && "正常状态不应触发报警");
|
||||
|
||||
// 测试5: 获取最新状态
|
||||
StatusLog latest = svc.getLatestStatus("AST_65537");
|
||||
assert(latest.assetId == "AST_65537" && "应返回正确资产的状态");
|
||||
|
||||
// 不存在的资产
|
||||
latest = svc.getLatestStatus("UNKNOWN");
|
||||
assert(latest.isAbnormal && "不存在的资产应标记异常");
|
||||
|
||||
// 测试6: 数据陈旧检查
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
svc.checkStaleData(10);
|
||||
StatusLog staleLog = svc.getLatestStatus("AST_65537");
|
||||
assert(staleLog.isAbnormal && "超过阈值后应标记为陈旧");
|
||||
assert(staleLog.statusCode == "STALE" && "陈旧数据状态码应为STALE");
|
||||
|
||||
std::cout << " SU-08 测试通过!" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试系统外观类
|
||||
*
|
||||
* @requirement(name="业务目标", id="REQ-BMP-001")
|
||||
* 测试系统初始化、完整业务流程的协调。
|
||||
*/
|
||||
static void testSystemIntegration() {
|
||||
std::cout << "[测试] BMP集成: 系统外观类" << std::endl;
|
||||
BattlefieldMissionPlanner bmp;
|
||||
|
||||
// 测试1: 初始化
|
||||
bool initialized = bmp.initialize();
|
||||
assert(initialized && "系统初始化应成功");
|
||||
|
||||
// 测试2: 获取各服务引用
|
||||
assert(&bmp.getEventService() != nullptr && "事件服务不应为空");
|
||||
assert(&bmp.getTemplateService() != nullptr && "模板服务不应为空");
|
||||
assert(&bmp.getPlanService() != nullptr && "计划服务不应为空");
|
||||
assert(&bmp.getDistributionService() != nullptr && "分发服务不应为空");
|
||||
assert(&bmp.getStatusMonitorService() != nullptr && "状态监控服务不应为空");
|
||||
|
||||
// 测试3: 运行主循环(不崩溃即可)
|
||||
bmp.run();
|
||||
|
||||
std::cout << " BMP集成测试通过!" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "========================================" << std::endl;
|
||||
std::cout << " 战场任务规划管理系统 - 单元测试" << std::endl;
|
||||
std::cout << "========================================" << std::endl << std::endl;
|
||||
|
||||
testEventReception();
|
||||
testEventStandardization();
|
||||
testEventQuery();
|
||||
testTemplateManagement();
|
||||
testPlanManagement();
|
||||
testDistribution();
|
||||
testStatusMonitoring();
|
||||
testSystemIntegration();
|
||||
|
||||
std::cout << "========================================" << std::endl;
|
||||
std::cout << " 全部测试通过!" << std::endl;
|
||||
std::cout << "========================================" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue