功能开发

This commit is contained in:
root 2026-06-09 13:14:15 +08:00
parent c6be24394e
commit 4b7a402ef7
7 changed files with 22609 additions and 0 deletions

24
CMakeLists.txt Normal file
View File

@ -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)

20590
events.ndjson Normal file

File diff suppressed because one or more lines are too long

30
generation.json Normal file

File diff suppressed because one or more lines are too long

564
include/app.hpp Normal file
View File

@ -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

663
src/app.cpp Normal file
View File

@ -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_toprioritystatus
*/
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")
*
* [4ID][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

347
src/main.cpp Normal file
View File

@ -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;
}

391
tests/basic_test.cpp Normal file
View File

@ -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;
}