生成代码工程
This commit is contained in:
parent
8c9b9e9814
commit
68c52570b3
|
|
@ -0,0 +1,28 @@
|
||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
project(ocpm VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
# C++17 标准
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
# MSVC UTF-8 支持
|
||||||
|
if (MSVC)
|
||||||
|
add_compile_options(/utf-8)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# 可执行目标
|
||||||
|
add_executable(ocpm
|
||||||
|
src/main.cpp
|
||||||
|
src/app.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(ocpm PRIVATE include)
|
||||||
|
|
||||||
|
# 测试目标
|
||||||
|
add_executable(basic_test
|
||||||
|
tests/basic_test.cpp
|
||||||
|
src/app.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(basic_test PRIVATE include)
|
||||||
42
README.md
42
README.md
|
|
@ -1,3 +1,41 @@
|
||||||
# 智能体开发平台-演示系统
|
# OCPM — 作战指挥计划管理系统
|
||||||
|
|
||||||
暂无描述
|
## 概述
|
||||||
|
|
||||||
|
OCPM (Operation Command Planning Manager) 是一个面向现代战争的作战指挥计划管理系统,支持从计划制定、优化、分发到执行监控的全流程闭环管理。本工程为其核心 C++ 后端原型。
|
||||||
|
|
||||||
|
## 功能模块
|
||||||
|
|
||||||
|
| 模块 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 计划管理 (PlanManager) | 集中式计划 CRUD、排序、对比、重构、HITL |
|
||||||
|
| 分布式计划 (DistributedPlanManager) | 分布式计划拓扑管理与节点重构 |
|
||||||
|
| 指令分发与执行监控 (DispatchManager) | 计划分发、资产状态监控、仪表盘/流程图/告警 |
|
||||||
|
| 综合可视化 (Dashboard) | 全局态势总览 |
|
||||||
|
|
||||||
|
## 数据结构
|
||||||
|
|
||||||
|
- **Plan_Info**:作战计划核心实体(plan_id, plan_name, status, priority, plan_type 等)
|
||||||
|
- **AssetStatus**:资产状态枚举(就绪/忙碌/故障/离线)
|
||||||
|
- 各类 JSON 接口数据模型已在 `include/app.hpp` 中定义
|
||||||
|
|
||||||
|
## 编译与运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 配置
|
||||||
|
cmake -B build
|
||||||
|
|
||||||
|
# 构建
|
||||||
|
cmake --build build
|
||||||
|
|
||||||
|
# 运行主程序
|
||||||
|
./build/ocpm
|
||||||
|
|
||||||
|
# 运行测试
|
||||||
|
./build/basic_test
|
||||||
|
```
|
||||||
|
|
||||||
|
## 环境要求
|
||||||
|
|
||||||
|
- C++17 编译器(GCC 8+, Clang 10+, MSVC 2019+)
|
||||||
|
- CMake ≥ 3.14
|
||||||
|
|
|
||||||
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,294 @@
|
||||||
|
#ifndef OCPM_APP_HPP
|
||||||
|
#define OCPM_APP_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
#include <chrono>
|
||||||
|
#include <ostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
/// @brief 命名空间 ocpm — 作战指挥计划管理系统核心逻辑
|
||||||
|
namespace ocpm {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 枚举定义
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/// @brief 计划状态
|
||||||
|
enum class PlanStatus : int {
|
||||||
|
DRAFT = 0, ///< 草稿
|
||||||
|
ACTIVE = 1, ///< 生效
|
||||||
|
ARCHIVED = 2 ///< 归档
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 计划类型
|
||||||
|
enum class PlanType : int {
|
||||||
|
CENTRALIZED = 0, ///< 集中式
|
||||||
|
DISTRIBUTED = 1 ///< 分布式
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 资产状态码 (SRS-OCPM_I_COM_001)
|
||||||
|
enum class AssetStatusCode : int {
|
||||||
|
READY = 0, ///< 就绪 (绿灯)
|
||||||
|
BUSY = 1, ///< 忙碌 (黄灯)
|
||||||
|
FAULT = 2, ///< 故障 (红灯)
|
||||||
|
OFFLINE = 3 ///< 离线 (灰色)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 排序方向 (SRS-OCPM_I_UI_002)
|
||||||
|
enum class SortDirection {
|
||||||
|
ASC, ///< 升序
|
||||||
|
DESC ///< 降序
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 异常等级
|
||||||
|
enum class AlertLevel {
|
||||||
|
INFO, ///< 信息
|
||||||
|
WARNING, ///< 警告
|
||||||
|
ERROR, ///< 错误
|
||||||
|
CRITICAL ///< 严重
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 核心数据结构
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/// @brief 作战计划实体 — 对应数据库 Plan_Info 表
|
||||||
|
struct PlanInfo {
|
||||||
|
std::string plan_id; ///< 计划唯一标识
|
||||||
|
std::string plan_name; ///< 计划名称
|
||||||
|
std::string create_time; ///< 创建时间 (ISO 8601)
|
||||||
|
std::string update_time; ///< 最后修改时间
|
||||||
|
PlanStatus status = PlanStatus::DRAFT; ///< 计划状态
|
||||||
|
int priority = 0; ///< 优先级 (0~100)
|
||||||
|
PlanType plan_type = PlanType::CENTRALIZED; ///< 计划类型
|
||||||
|
std::string creator; ///< 创建人
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 计划查询请求 (SRS-OCPM_I_UI_001)
|
||||||
|
struct PlanQueryRequest {
|
||||||
|
int status_filter = -1; ///< 按状态过滤, -1 表示不限
|
||||||
|
int priority_min = 0;
|
||||||
|
std::string keyword; ///< 关键字模糊匹配
|
||||||
|
int page = 1; ///< 页码
|
||||||
|
int page_size = 100; ///< 每页条数, 上限 100
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 排序参数 (SRS-OCPM_I_UI_002)
|
||||||
|
struct SortParam {
|
||||||
|
std::string field; ///< 排序字段名 (如 "priority", "create_time")
|
||||||
|
SortDirection direction = SortDirection::ASC;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 网络拓扑节点 — 用于分布式计划 (SRS-OCPM_I_DB_002)
|
||||||
|
struct TopoNode {
|
||||||
|
std::string node_id; ///< 节点标识
|
||||||
|
std::string label; ///< 显示标签
|
||||||
|
double x = 0.0; ///< 布局坐标 X
|
||||||
|
double y = 0.0; ///< 布局坐标 Y
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 网络拓扑边
|
||||||
|
struct TopoEdge {
|
||||||
|
std::string edge_id; ///< 边标识
|
||||||
|
std::string source_id; ///< 源节点
|
||||||
|
std::string target_id; ///< 目标节点
|
||||||
|
int bandwidth = 0; ///< 带宽 (Mbps)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 分布式计划拓扑数据
|
||||||
|
struct DistributedPlanGraph {
|
||||||
|
std::vector<TopoNode> nodes; ///< 节点列表
|
||||||
|
std::vector<TopoEdge> edges; ///< 边列表
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief HITL 事件 (SRS-OCPM_I_ALG_001)
|
||||||
|
struct HitlEvent {
|
||||||
|
std::string request_id; ///< 请求标识
|
||||||
|
std::string reason; ///< 需要人工干预的原因
|
||||||
|
std::vector<std::string> options; ///< 可选方案列表
|
||||||
|
std::string deadline; ///< 截止时间
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 重构指令 (SRS-OCPM_I_UI_007)
|
||||||
|
struct ReconstructCommand {
|
||||||
|
std::string plan_id; ///< 目标计划 ID
|
||||||
|
std::vector<std::string> modifications; ///< 修改描述列表
|
||||||
|
std::vector<std::string> target_tasks; ///< 目标任务列表
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 重构结果 (SRS-OCPM_O_UI_007)
|
||||||
|
struct ReconstructResult {
|
||||||
|
bool success = false; ///< 是否成功
|
||||||
|
std::string message; ///< 结果消息
|
||||||
|
std::string new_version; ///< 新版本号 (成功时)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 子任务节点 — 用于流程图 (SRS-OCPM_I_SYS_004)
|
||||||
|
struct TaskNode {
|
||||||
|
std::string task_id; ///< 任务标识
|
||||||
|
std::string name; ///< 任务名称
|
||||||
|
std::string status; ///< 状态 (pending/running/completed/failed)
|
||||||
|
std::vector<std::string> dependency_ids; ///< 依赖的任务 ID 列表
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 异常事件 (SRS-OCPM_I_SYS_005)
|
||||||
|
struct AlertEvent {
|
||||||
|
int code; ///< 异常编码
|
||||||
|
AlertLevel level = AlertLevel::INFO;
|
||||||
|
std::string timestamp; ///< 发生时间
|
||||||
|
std::string task_id; ///< 关联任务
|
||||||
|
std::string description; ///< 描述
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 执行统计数据 (SRS-OCPM_I_SYS_003)
|
||||||
|
struct ExecutionStats {
|
||||||
|
int completed_tasks = 0; ///< 已完成任务数
|
||||||
|
int total_tasks = 0; ///< 总任务数
|
||||||
|
double remaining_time = 0.0; ///< 剩余时间 (分钟)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 仪表盘聚合数据 (SRS-OCPM_I_SYS_006)
|
||||||
|
struct DashboardData {
|
||||||
|
ExecutionStats execution; ///< 执行进度
|
||||||
|
double resource_rate; ///< 资源剩余率 (0.0~1.0)
|
||||||
|
std::vector<AlertEvent> recent_alerts; ///< 最近异常
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 模块管理器类声明
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/// @brief 计划管理器 — 负责集中式计划的 CRUD、排序、对比、重构
|
||||||
|
class PlanManager {
|
||||||
|
public:
|
||||||
|
PlanManager() = default;
|
||||||
|
virtual ~PlanManager() = default;
|
||||||
|
|
||||||
|
/// @brief 查询计划列表
|
||||||
|
/// @param query 查询请求参数
|
||||||
|
/// @param sort 排序参数
|
||||||
|
/// @return 计划列表
|
||||||
|
std::vector<PlanInfo> queryPlans(const PlanQueryRequest& query,
|
||||||
|
const SortParam& sort = {"priority", SortDirection::DESC});
|
||||||
|
|
||||||
|
/// @brief 获取单个计划详情
|
||||||
|
/// @param plan_id 计划 ID
|
||||||
|
/// @return PlanInfo
|
||||||
|
/// @throws std::invalid_argument 如果 plan_id 不存在
|
||||||
|
PlanInfo getPlanDetail(const std::string& plan_id);
|
||||||
|
|
||||||
|
/// @brief 对比两个计划
|
||||||
|
/// @param id_a 计划 A ID
|
||||||
|
/// @param id_b 计划 B ID
|
||||||
|
/// @return 差异描述列表 (每项格式: "字段名: A值 vs B值")
|
||||||
|
std::vector<std::string> comparePlans(const std::string& id_a, const std::string& id_b);
|
||||||
|
|
||||||
|
/// @brief 执行重构操作
|
||||||
|
/// @param cmd 重构指令
|
||||||
|
/// @return 重构结果
|
||||||
|
ReconstructResult reconstruct(const ReconstructCommand& cmd);
|
||||||
|
|
||||||
|
/// @brief 提交 HITL 事件通知
|
||||||
|
/// @param event HITL 事件
|
||||||
|
void notifyHitlEvent(const HitlEvent& event);
|
||||||
|
|
||||||
|
/// @brief 设置算法进度回调
|
||||||
|
/// @param cb 回调函数, 参数为 (stage, progress%)
|
||||||
|
void setAlgorithmProgressCallback(std::function<void(const std::string&, int)> cb);
|
||||||
|
|
||||||
|
/// @brief 模拟加载示例数据
|
||||||
|
void loadSampleData();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<PlanInfo> plans_;
|
||||||
|
std::function<void(const std::string&, int)> algo_callback_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 分布式计划管理器
|
||||||
|
class DistributedPlanManager {
|
||||||
|
public:
|
||||||
|
DistributedPlanManager() = default;
|
||||||
|
virtual ~DistributedPlanManager() = default;
|
||||||
|
|
||||||
|
/// @brief 获取当前拓扑图
|
||||||
|
const DistributedPlanGraph& getGraph() const { return graph_; }
|
||||||
|
|
||||||
|
/// @brief 添加节点
|
||||||
|
/// @param node 新节点
|
||||||
|
void addNode(const TopoNode& node);
|
||||||
|
|
||||||
|
/// @brief 移除节点 (同时移除关联边)
|
||||||
|
/// @param node_id 节点 ID
|
||||||
|
void removeNode(const std::string& node_id);
|
||||||
|
|
||||||
|
/// @brief 添加边
|
||||||
|
/// @param edge 新边
|
||||||
|
void addEdge(const TopoEdge& edge);
|
||||||
|
|
||||||
|
/// @brief 移除边
|
||||||
|
/// @param edge_id 边 ID
|
||||||
|
void removeEdge(const std::string& edge_id);
|
||||||
|
|
||||||
|
/// @brief 模拟加载示例拓扑
|
||||||
|
void loadSampleData();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DistributedPlanGraph graph_;
|
||||||
|
|
||||||
|
/// @brief 检查图连通性 (简单 BFS)
|
||||||
|
bool isConnected() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief 指令分发与执行监控管理器
|
||||||
|
class DispatchManager {
|
||||||
|
public:
|
||||||
|
DispatchManager() = default;
|
||||||
|
virtual ~DispatchManager() = default;
|
||||||
|
|
||||||
|
/// @brief 分发计划至多个资产
|
||||||
|
/// @param plan_id 计划 ID
|
||||||
|
/// @param asset_ids 目标资产 ID 列表
|
||||||
|
/// @return 成功分发的资产数
|
||||||
|
int dispatchPlan(const std::string& plan_id, const std::vector<std::string>& asset_ids);
|
||||||
|
|
||||||
|
/// @brief 查询资产状态
|
||||||
|
/// @param asset_id 资产 ID
|
||||||
|
/// @return 资产状态码
|
||||||
|
AssetStatusCode getAssetStatus(const std::string& asset_id);
|
||||||
|
|
||||||
|
/// @brief 获取执行统计
|
||||||
|
/// @return ExecutionStats
|
||||||
|
ExecutionStats getExecutionStats() const;
|
||||||
|
|
||||||
|
/// @brief 获取仪表盘数据
|
||||||
|
/// @return DashboardData
|
||||||
|
DashboardData getDashboardData() const;
|
||||||
|
|
||||||
|
/// @brief 获取子任务流程图
|
||||||
|
/// @return 子任务列表
|
||||||
|
std::vector<TaskNode> getTaskFlow() const;
|
||||||
|
|
||||||
|
/// @brief 获取未清除的异常事件列表
|
||||||
|
/// @param level_filter 按等级过滤, 传入 nullptr 不限制
|
||||||
|
std::vector<AlertEvent> getAlerts(const AlertLevel* level_filter = nullptr) const;
|
||||||
|
|
||||||
|
/// @brief 清除所有异常
|
||||||
|
void clearAlerts();
|
||||||
|
|
||||||
|
/// @brief 模拟加载示例数据
|
||||||
|
void loadSampleData();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, AssetStatusCode> asset_statuses_;
|
||||||
|
std::vector<AlertEvent> alerts_;
|
||||||
|
std::vector<TaskNode> task_flow_;
|
||||||
|
ExecutionStats stats_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ocpm
|
||||||
|
|
||||||
|
#endif // OCPM_APP_HPP
|
||||||
|
|
@ -0,0 +1,310 @@
|
||||||
|
#include "app.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
#include <set>
|
||||||
|
#include <queue>
|
||||||
|
#include <random>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
namespace ocpm {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// PlanManager 实现
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
std::vector<PlanInfo> PlanManager::queryPlans(const PlanQueryRequest& query,
|
||||||
|
const SortParam& sort) {
|
||||||
|
// 1. 过滤
|
||||||
|
std::vector<PlanInfo> result;
|
||||||
|
for (const auto& p : plans_) {
|
||||||
|
if (query.status_filter >= 0 && static_cast<int>(p.status) != query.status_filter)
|
||||||
|
continue;
|
||||||
|
if (p.priority < query.priority_min)
|
||||||
|
continue;
|
||||||
|
if (!query.keyword.empty()) {
|
||||||
|
auto pos = p.plan_name.find(query.keyword);
|
||||||
|
bool found = (pos != std::string::npos) ||
|
||||||
|
(p.plan_id.find(query.keyword) != std::string::npos);
|
||||||
|
if (!found)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.push_back(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 排序
|
||||||
|
std::sort(result.begin(), result.end(),
|
||||||
|
[&sort](const PlanInfo& a, const PlanInfo& b) {
|
||||||
|
int cmp = 0;
|
||||||
|
if (sort.field == "priority") {
|
||||||
|
cmp = (a.priority < b.priority) ? -1 : (a.priority > b.priority ? 1 : 0);
|
||||||
|
} else if (sort.field == "create_time") {
|
||||||
|
cmp = a.create_time.compare(b.create_time);
|
||||||
|
} else if (sort.field == "update_time") {
|
||||||
|
cmp = a.update_time.compare(b.update_time);
|
||||||
|
} else if (sort.field == "plan_name") {
|
||||||
|
cmp = a.plan_name.compare(b.plan_name);
|
||||||
|
} else if (sort.field == "status") {
|
||||||
|
cmp = static_cast<int>(a.status) - static_cast<int>(b.status);
|
||||||
|
}
|
||||||
|
return (sort.direction == SortDirection::ASC) ? (cmp < 0) : (cmp > 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. 分页
|
||||||
|
size_t start = static_cast<size_t>((query.page - 1)) * query.page_size;
|
||||||
|
if (start >= result.size())
|
||||||
|
return {};
|
||||||
|
size_t end = std::min(start + query.page_size, result.size());
|
||||||
|
return std::vector<PlanInfo>(result.begin() + static_cast<long>(start),
|
||||||
|
result.begin() + static_cast<long>(end));
|
||||||
|
}
|
||||||
|
|
||||||
|
PlanInfo PlanManager::getPlanDetail(const std::string& plan_id) {
|
||||||
|
for (const auto& p : plans_) {
|
||||||
|
if (p.plan_id == plan_id)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
throw std::invalid_argument("Plan not found: " + plan_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> PlanManager::comparePlans(const std::string& id_a,
|
||||||
|
const std::string& id_b) {
|
||||||
|
PlanInfo a = getPlanDetail(id_a);
|
||||||
|
PlanInfo b = getPlanDetail(id_b);
|
||||||
|
std::vector<std::string> diffs;
|
||||||
|
if (a.plan_name != b.plan_name)
|
||||||
|
diffs.push_back("plan_name: \"" + a.plan_name + "\" vs \"" + b.plan_name + "\"");
|
||||||
|
if (a.priority != b.priority)
|
||||||
|
diffs.push_back("priority: " + std::to_string(a.priority) + " vs " + std::to_string(b.priority));
|
||||||
|
if (a.status != b.status)
|
||||||
|
diffs.push_back("status: " + std::to_string(static_cast<int>(a.status)) +
|
||||||
|
" vs " + std::to_string(static_cast<int>(b.status)));
|
||||||
|
if (a.plan_type != b.plan_type)
|
||||||
|
diffs.push_back("plan_type: " + std::to_string(static_cast<int>(a.plan_type)) +
|
||||||
|
" vs " + std::to_string(static_cast<int>(b.plan_type)));
|
||||||
|
if (diffs.empty())
|
||||||
|
diffs.push_back("(no differences)");
|
||||||
|
return diffs;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReconstructResult PlanManager::reconstruct(const ReconstructCommand& cmd) {
|
||||||
|
// 模拟重构:找到对应计划,更新版本
|
||||||
|
for (auto& p : plans_) {
|
||||||
|
if (p.plan_id == cmd.plan_id) {
|
||||||
|
p.update_time = "2025-01-15T10:30:00Z";
|
||||||
|
ReconstructResult r;
|
||||||
|
r.success = true;
|
||||||
|
r.message = "重构成功,已应用 " + std::to_string(cmd.modifications.size()) + " 项修改";
|
||||||
|
r.new_version = p.plan_id + "-v2";
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReconstructResult r;
|
||||||
|
r.success = false;
|
||||||
|
r.message = "计划未找到: " + cmd.plan_id;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanManager::notifyHitlEvent(const HitlEvent& event) {
|
||||||
|
/// @brief 模拟 HITL 通知: 记录事件到日志 (实际系统会推送至前端)
|
||||||
|
(void)event;
|
||||||
|
// 实际实现中会触发前端铃铛红点与弹窗
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanManager::setAlgorithmProgressCallback(
|
||||||
|
std::function<void(const std::string&, int)> cb) {
|
||||||
|
algo_callback_ = std::move(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanManager::loadSampleData() {
|
||||||
|
plans_.clear();
|
||||||
|
auto make = [](std::string id, std::string name, PlanStatus st, int pri,
|
||||||
|
PlanType tp, std::string creator) {
|
||||||
|
PlanInfo p;
|
||||||
|
p.plan_id = std::move(id);
|
||||||
|
p.plan_name = std::move(name);
|
||||||
|
p.create_time = "2025-01-10T08:00:00Z";
|
||||||
|
p.update_time = "2025-01-12T14:30:00Z";
|
||||||
|
p.status = st;
|
||||||
|
p.priority = pri;
|
||||||
|
p.plan_type = tp;
|
||||||
|
p.creator = std::move(creator);
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
plans_.push_back(make("PLAN-001", "突击行动-甲", PlanStatus::ACTIVE, 90, PlanType::CENTRALIZED, "张指挥"));
|
||||||
|
plans_.push_back(make("PLAN-002", "防御布署-乙", PlanStatus::DRAFT, 70, PlanType::CENTRALIZED, "李参谋"));
|
||||||
|
plans_.push_back(make("PLAN-003", "侦察协同-丙", PlanStatus::ACTIVE, 85, PlanType::DISTRIBUTED, "王处长"));
|
||||||
|
plans_.push_back(make("PLAN-004", "后方支援-丁", PlanStatus::ARCHIVED,50, PlanType::CENTRALIZED, "赵主任"));
|
||||||
|
plans_.push_back(make("PLAN-005", "电子对抗-戊", PlanStatus::DRAFT, 95, PlanType::DISTRIBUTED, "孙队长"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// DistributedPlanManager 实现
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void DistributedPlanManager::addNode(const TopoNode& node) {
|
||||||
|
// 去重
|
||||||
|
for (const auto& n : graph_.nodes) {
|
||||||
|
if (n.node_id == node.node_id)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
graph_.nodes.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DistributedPlanManager::removeNode(const std::string& node_id) {
|
||||||
|
auto& nodes = graph_.nodes;
|
||||||
|
nodes.erase(
|
||||||
|
std::remove_if(nodes.begin(), nodes.end(),
|
||||||
|
[&](const TopoNode& n) { return n.node_id == node_id; }),
|
||||||
|
nodes.end());
|
||||||
|
|
||||||
|
// 移除相关边
|
||||||
|
auto& edges = graph_.edges;
|
||||||
|
edges.erase(
|
||||||
|
std::remove_if(edges.begin(), edges.end(),
|
||||||
|
[&](const TopoEdge& e) {
|
||||||
|
return e.source_id == node_id || e.target_id == node_id;
|
||||||
|
}),
|
||||||
|
edges.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DistributedPlanManager::addEdge(const TopoEdge& edge) {
|
||||||
|
for (const auto& e : graph_.edges) {
|
||||||
|
if (e.edge_id == edge.edge_id)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
graph_.edges.push_back(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DistributedPlanManager::removeEdge(const std::string& edge_id) {
|
||||||
|
auto& edges = graph_.edges;
|
||||||
|
edges.erase(
|
||||||
|
std::remove_if(edges.begin(), edges.end(),
|
||||||
|
[&](const TopoEdge& e) { return e.edge_id == edge_id; }),
|
||||||
|
edges.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DistributedPlanManager::isConnected() const {
|
||||||
|
if (graph_.nodes.empty())
|
||||||
|
return true;
|
||||||
|
std::set<std::string> visited;
|
||||||
|
std::queue<std::string> q;
|
||||||
|
q.push(graph_.nodes.front().node_id);
|
||||||
|
visited.insert(graph_.nodes.front().node_id);
|
||||||
|
while (!q.empty()) {
|
||||||
|
auto cur = q.front(); q.pop();
|
||||||
|
for (const auto& e : graph_.edges) {
|
||||||
|
std::string neighbor;
|
||||||
|
if (e.source_id == cur)
|
||||||
|
neighbor = e.target_id;
|
||||||
|
else if (e.target_id == cur)
|
||||||
|
neighbor = e.source_id;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
if (visited.find(neighbor) == visited.end()) {
|
||||||
|
visited.insert(neighbor);
|
||||||
|
q.push(neighbor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return visited.size() == graph_.nodes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DistributedPlanManager::loadSampleData() {
|
||||||
|
graph_.nodes.clear();
|
||||||
|
graph_.edges.clear();
|
||||||
|
|
||||||
|
graph_.nodes.push_back({"NODE-01", "前沿指挥所", 100.0, 200.0});
|
||||||
|
graph_.nodes.push_back({"NODE-02", "火力单元-A", 300.0, 100.0});
|
||||||
|
graph_.nodes.push_back({"NODE-03", "侦察单元-B", 300.0, 300.0});
|
||||||
|
graph_.nodes.push_back({"NODE-04", "通信中继-C", 500.0, 200.0});
|
||||||
|
|
||||||
|
graph_.edges.push_back({"EDGE-01", "NODE-01", "NODE-02", 100});
|
||||||
|
graph_.edges.push_back({"EDGE-02", "NODE-01", "NODE-03", 100});
|
||||||
|
graph_.edges.push_back({"EDGE-03", "NODE-02", "NODE-04", 50});
|
||||||
|
graph_.edges.push_back({"EDGE-04", "NODE-03", "NODE-04", 50});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// DispatchManager 实现
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
int DispatchManager::dispatchPlan(const std::string& plan_id,
|
||||||
|
const std::vector<std::string>& asset_ids) {
|
||||||
|
/// @brief 模拟并发分发: 简单计数
|
||||||
|
(void)plan_id;
|
||||||
|
int success_count = 0;
|
||||||
|
for (const auto& aid : asset_ids) {
|
||||||
|
auto it = asset_statuses_.find(aid);
|
||||||
|
if (it != asset_statuses_.end() && it->second == AssetStatusCode::READY) {
|
||||||
|
success_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetStatusCode DispatchManager::getAssetStatus(const std::string& asset_id) {
|
||||||
|
auto it = asset_statuses_.find(asset_id);
|
||||||
|
if (it != asset_statuses_.end())
|
||||||
|
return it->second;
|
||||||
|
return AssetStatusCode::OFFLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecutionStats DispatchManager::getExecutionStats() const {
|
||||||
|
return stats_;
|
||||||
|
}
|
||||||
|
|
||||||
|
DashboardData DispatchManager::getDashboardData() const {
|
||||||
|
DashboardData dd;
|
||||||
|
dd.execution = stats_;
|
||||||
|
dd.resource_rate = 0.72;
|
||||||
|
dd.recent_alerts = alerts_;
|
||||||
|
return dd;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<TaskNode> DispatchManager::getTaskFlow() const {
|
||||||
|
return task_flow_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AlertEvent> DispatchManager::getAlerts(const AlertLevel* level_filter) const {
|
||||||
|
if (!level_filter)
|
||||||
|
return alerts_;
|
||||||
|
std::vector<AlertEvent> filtered;
|
||||||
|
for (const auto& a : alerts_) {
|
||||||
|
if (a.level == *level_filter)
|
||||||
|
filtered.push_back(a);
|
||||||
|
}
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispatchManager::clearAlerts() {
|
||||||
|
alerts_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispatchManager::loadSampleData() {
|
||||||
|
// 资产状态
|
||||||
|
asset_statuses_["ASSET-001"] = AssetStatusCode::READY;
|
||||||
|
asset_statuses_["ASSET-002"] = AssetStatusCode::BUSY;
|
||||||
|
asset_statuses_["ASSET-003"] = AssetStatusCode::FAULT;
|
||||||
|
asset_statuses_["ASSET-004"] = AssetStatusCode::READY;
|
||||||
|
asset_statuses_["ASSET-005"] = AssetStatusCode::OFFLINE;
|
||||||
|
|
||||||
|
// 异常事件
|
||||||
|
alerts_.push_back({1001, AlertLevel::WARNING, "2025-01-14T09:15:00Z",
|
||||||
|
"TASK-03", "通信链路延迟超过阈值"});
|
||||||
|
alerts_.push_back({1002, AlertLevel::ERROR, "2025-01-14T09:20:00Z",
|
||||||
|
"TASK-05", "资产 ASSET-003 无响应"});
|
||||||
|
|
||||||
|
// 子任务流程图
|
||||||
|
task_flow_.push_back({"TASK-01", "侦察定位", "completed", {}});
|
||||||
|
task_flow_.push_back({"TASK-02", "目标锁定", "running", {"TASK-01"}});
|
||||||
|
task_flow_.push_back({"TASK-03", "火力计算", "pending", {"TASK-02"}});
|
||||||
|
task_flow_.push_back({"TASK-04", "打击执行", "pending", {"TASK-03"}});
|
||||||
|
task_flow_.push_back({"TASK-05", "效果评估", "pending", {"TASK-04"}});
|
||||||
|
|
||||||
|
// 执行统计
|
||||||
|
stats_.completed_tasks = 1;
|
||||||
|
stats_.total_tasks = 5;
|
||||||
|
stats_.remaining_time = 28.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ocpm
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
#include "app.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
/// @brief 打印分隔线
|
||||||
|
static void printSeparator() {
|
||||||
|
std::cout << "----------------------------------------\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 打印单个 PlanInfo
|
||||||
|
/// @param p 计划信息
|
||||||
|
static void printPlan(const ocpm::PlanInfo& p) {
|
||||||
|
std::cout << " ID: " << p.plan_id << "\n"
|
||||||
|
<< " 名称: " << p.plan_name << "\n"
|
||||||
|
<< " 状态: " << static_cast<int>(p.status) << " (0=草稿 1=生效 2=归档)\n"
|
||||||
|
<< " 优先级: " << p.priority << "\n"
|
||||||
|
<< " 类型: " << (p.plan_type == ocpm::PlanType::CENTRALIZED ? "集中式" : "分布式") << "\n"
|
||||||
|
<< " 创建人: " << p.creator << "\n"
|
||||||
|
<< " 创建时间: " << p.create_time << "\n"
|
||||||
|
<< " 更新时间: " << p.update_time << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 主入口 — 演示 OCPM 系统核心功能
|
||||||
|
int main() {
|
||||||
|
std::cout << "========================================\n";
|
||||||
|
std::cout << " OCPM - 作战指挥计划管理系统 v1.0\n";
|
||||||
|
std::cout << "========================================\n\n";
|
||||||
|
|
||||||
|
// ---- 计划管理演示 ----
|
||||||
|
std::cout << "[1] 计划管理模块演示\n";
|
||||||
|
printSeparator();
|
||||||
|
|
||||||
|
ocpm::PlanManager pm;
|
||||||
|
pm.loadSampleData();
|
||||||
|
|
||||||
|
// 查询所有计划
|
||||||
|
ocpm::PlanQueryRequest all_query;
|
||||||
|
all_query.page_size = 100;
|
||||||
|
auto plans = pm.queryPlans(all_query);
|
||||||
|
std::cout << " 加载了 " << plans.size() << " 个示例计划:\n";
|
||||||
|
for (const auto& p : plans) {
|
||||||
|
std::cout << " - " << p.plan_id << " | " << p.plan_name << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按优先级降序排序查询
|
||||||
|
ocpm::SortParam sort_by_prio{"priority", ocpm::SortDirection::DESC};
|
||||||
|
auto sorted = pm.queryPlans(all_query, sort_by_prio);
|
||||||
|
std::cout << "\n 按优先级降序排列:\n";
|
||||||
|
for (const auto& p : sorted) {
|
||||||
|
std::cout << " " << p.plan_id << " (优先级=" << p.priority << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取详情
|
||||||
|
try {
|
||||||
|
auto detail = pm.getPlanDetail("PLAN-001");
|
||||||
|
std::cout << "\n 计划详情 (PLAN-001):\n";
|
||||||
|
printPlan(detail);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << " 错误: " << e.what() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对比两个计划
|
||||||
|
auto diffs = pm.comparePlans("PLAN-001", "PLAN-002");
|
||||||
|
std::cout << "\n 计划对比 (PLAN-001 vs PLAN-002):\n";
|
||||||
|
for (const auto& d : diffs) {
|
||||||
|
std::cout << " - " << d << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重构
|
||||||
|
ocpm::ReconstructCommand rc;
|
||||||
|
rc.plan_id = "PLAN-002";
|
||||||
|
rc.modifications = {"调整优先级至85", "修改目标区域"};
|
||||||
|
auto reconf_result = pm.reconstruct(rc);
|
||||||
|
std::cout << "\n 重构结果: " << (reconf_result.success ? "成功" : "失败")
|
||||||
|
<< " | " << reconf_result.message << "\n";
|
||||||
|
|
||||||
|
// ---- 分布式计划演示 ----
|
||||||
|
std::cout << "\n[2] 分布式计划模块演示\n";
|
||||||
|
printSeparator();
|
||||||
|
|
||||||
|
ocpm::DistributedPlanManager dpm;
|
||||||
|
dpm.loadSampleData();
|
||||||
|
const auto& graph = dpm.getGraph();
|
||||||
|
std::cout << " 拓扑: " << graph.nodes.size() << " 节点, "
|
||||||
|
<< graph.edges.size() << " 条边\n";
|
||||||
|
for (const auto& n : graph.nodes) {
|
||||||
|
std::cout << " 节点 " << n.node_id << " [" << n.label << "]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加节点
|
||||||
|
ocpm::TopoNode new_node{"NODE-05", "无人机蜂群", 700.0, 100.0};
|
||||||
|
dpm.addNode(new_node);
|
||||||
|
dpm.addEdge({"EDGE-05", "NODE-04", "NODE-05", 200});
|
||||||
|
std::cout << " 添加新节点后: " << dpm.getGraph().nodes.size() << " 节点\n";
|
||||||
|
|
||||||
|
// ---- 指令分发与监控演示 ----
|
||||||
|
std::cout << "\n[3] 指令分发与执行监控演示\n";
|
||||||
|
printSeparator();
|
||||||
|
|
||||||
|
ocpm::DispatchManager dm;
|
||||||
|
dm.loadSampleData();
|
||||||
|
|
||||||
|
// 查询资产状态
|
||||||
|
std::cout << " 资产状态:\n";
|
||||||
|
for (const auto& id : {"ASSET-001", "ASSET-002", "ASSET-003", "ASSET-004", "ASSET-005"}) {
|
||||||
|
auto st = dm.getAssetStatus(id);
|
||||||
|
std::cout << " " << id << " -> ";
|
||||||
|
switch (st) {
|
||||||
|
case ocpm::AssetStatusCode::READY: std::cout << "就绪(绿)"; break;
|
||||||
|
case ocpm::AssetStatusCode::BUSY: std::cout << "忙碌(黄)"; break;
|
||||||
|
case ocpm::AssetStatusCode::FAULT: std::cout << "故障(红)"; break;
|
||||||
|
case ocpm::AssetStatusCode::OFFLINE:std::cout << "离线(灰)"; break;
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分发
|
||||||
|
int sent = dm.dispatchPlan("PLAN-001", {"ASSET-001", "ASSET-002", "ASSET-003"});
|
||||||
|
std::cout << "\n 分发结果: " << sent << " / 3 个资产成功接收\n";
|
||||||
|
|
||||||
|
// 异常告警
|
||||||
|
auto alerts = dm.getAlerts();
|
||||||
|
std::cout << "\n 当前异常告警: " << alerts.size() << " 条\n";
|
||||||
|
for (const auto& a : alerts) {
|
||||||
|
std::cout << " [" << a.timestamp << "] 等级="
|
||||||
|
<< static_cast<int>(a.level) << " | " << a.description << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 仪表盘
|
||||||
|
auto dash = dm.getDashboardData();
|
||||||
|
std::cout << "\n 执行仪表盘:\n";
|
||||||
|
std::cout << " 进度: " << dash.execution.completed_tasks << "/"
|
||||||
|
<< dash.execution.total_tasks << " 任务\n";
|
||||||
|
std::cout << " 剩余时间: " << dash.execution.remaining_time << " 分钟\n";
|
||||||
|
std::cout << " 资源剩余率: " << std::fixed << std::setprecision(1)
|
||||||
|
<< (dash.resource_rate * 100.0) << "%\n";
|
||||||
|
|
||||||
|
// 子任务流程图
|
||||||
|
auto tasks = dm.getTaskFlow();
|
||||||
|
std::cout << "\n 子任务流程图 (" << tasks.size() << " 个任务):\n";
|
||||||
|
for (const auto& t : tasks) {
|
||||||
|
std::cout << " " << t.task_id << " [" << t.name << "] -> " << t.status << "\n";
|
||||||
|
if (!t.dependency_ids.empty()) {
|
||||||
|
std::cout << " 依赖: ";
|
||||||
|
for (const auto& dep : t.dependency_ids)
|
||||||
|
std::cout << dep << " ";
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\n========================================\n";
|
||||||
|
std::cout << " 演示结束\n";
|
||||||
|
std::cout << "========================================\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,173 @@
|
||||||
|
#include "app.hpp"
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/// @brief 测试 PlanManager 基本功能
|
||||||
|
static void test_plan_manager() {
|
||||||
|
std::cout << "[测试] PlanManager\n";
|
||||||
|
|
||||||
|
ocpm::PlanManager pm;
|
||||||
|
pm.loadSampleData();
|
||||||
|
|
||||||
|
// 测试查询全部
|
||||||
|
ocpm::PlanQueryRequest all_q;
|
||||||
|
all_q.page_size = 100;
|
||||||
|
auto plans = pm.queryPlans(all_q);
|
||||||
|
assert(plans.size() == 5 && "应加载 5 个示例计划");
|
||||||
|
|
||||||
|
// 测试按状态过滤
|
||||||
|
ocpm::PlanQueryRequest active_q;
|
||||||
|
active_q.status_filter = static_cast<int>(ocpm::PlanStatus::ACTIVE);
|
||||||
|
auto active = pm.queryPlans(active_q);
|
||||||
|
assert(active.size() == 2 && "应有 2 个生效计划");
|
||||||
|
|
||||||
|
// 测试按关键字过滤
|
||||||
|
ocpm::PlanQueryRequest kw_q;
|
||||||
|
kw_q.keyword = "侦察";
|
||||||
|
auto kw = pm.queryPlans(kw_q);
|
||||||
|
assert(kw.size() == 1 && "关键字 '侦察' 应匹配 1 个计划");
|
||||||
|
assert(kw[0].plan_id == "PLAN-003");
|
||||||
|
|
||||||
|
// 测试排序 (按优先级降序)
|
||||||
|
ocpm::SortParam desc_prio{"priority", ocpm::SortDirection::DESC};
|
||||||
|
auto sorted = pm.queryPlans(all_q, desc_prio);
|
||||||
|
assert(!sorted.empty());
|
||||||
|
assert(sorted[0].priority >= sorted[1].priority);
|
||||||
|
|
||||||
|
// 测试获取详情
|
||||||
|
auto detail = pm.getPlanDetail("PLAN-001");
|
||||||
|
assert(detail.plan_id == "PLAN-001");
|
||||||
|
assert(detail.plan_name == "突击行动-甲");
|
||||||
|
|
||||||
|
// 测试获取不存在的计划
|
||||||
|
bool caught = false;
|
||||||
|
try {
|
||||||
|
pm.getPlanDetail("NONEXIST");
|
||||||
|
} catch (const std::invalid_argument&) {
|
||||||
|
caught = true;
|
||||||
|
}
|
||||||
|
assert(caught && "应抛出 invalid_argument");
|
||||||
|
|
||||||
|
// 测试对比
|
||||||
|
auto diffs = pm.comparePlans("PLAN-001", "PLAN-002");
|
||||||
|
assert(!diffs.empty());
|
||||||
|
|
||||||
|
// 测试重构
|
||||||
|
ocpm::ReconstructCommand rc;
|
||||||
|
rc.plan_id = "PLAN-002";
|
||||||
|
rc.modifications = {"测试修改"};
|
||||||
|
auto result = pm.reconstruct(rc);
|
||||||
|
assert(result.success);
|
||||||
|
assert(result.new_version.find("v2") != std::string::npos);
|
||||||
|
|
||||||
|
// 测试 HITL 通知不会崩溃
|
||||||
|
ocpm::HitlEvent hitl;
|
||||||
|
hitl.request_id = "REQ-001";
|
||||||
|
hitl.reason = "需要人工确认目标";
|
||||||
|
hitl.options = {"方案A", "方案B"};
|
||||||
|
pm.notifyHitlEvent(hitl); // 确保不崩溃
|
||||||
|
|
||||||
|
std::cout << " ✓ 所有 PlanManager 测试通过\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试 DistributedPlanManager 基本功能
|
||||||
|
static void test_distributed_plan_manager() {
|
||||||
|
std::cout << "[测试] DistributedPlanManager\n";
|
||||||
|
|
||||||
|
ocpm::DistributedPlanManager dpm;
|
||||||
|
dpm.loadSampleData();
|
||||||
|
assert(dpm.getGraph().nodes.size() == 4);
|
||||||
|
assert(dpm.getGraph().edges.size() == 4);
|
||||||
|
|
||||||
|
// 添加节点
|
||||||
|
ocpm::TopoNode n{"NODE-X", "测试节点", 0, 0};
|
||||||
|
dpm.addNode(n);
|
||||||
|
assert(dpm.getGraph().nodes.size() == 5);
|
||||||
|
|
||||||
|
// 重复添加不应增加
|
||||||
|
dpm.addNode(n);
|
||||||
|
assert(dpm.getGraph().nodes.size() == 5);
|
||||||
|
|
||||||
|
// 添加边
|
||||||
|
ocpm::TopoEdge e{"EDGE-X", "NODE-X", "NODE-01", 100};
|
||||||
|
dpm.addEdge(e);
|
||||||
|
assert(dpm.getGraph().edges.size() == 5);
|
||||||
|
|
||||||
|
// 移除边
|
||||||
|
dpm.removeEdge("EDGE-X");
|
||||||
|
assert(dpm.getGraph().edges.size() == 4);
|
||||||
|
|
||||||
|
// 移除节点 (应同时移除关联边)
|
||||||
|
dpm.removeNode("NODE-X");
|
||||||
|
assert(dpm.getGraph().nodes.size() == 4);
|
||||||
|
|
||||||
|
std::cout << " ✓ 所有 DistributedPlanManager 测试通过\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 测试 DispatchManager 基本功能
|
||||||
|
static void test_dispatch_manager() {
|
||||||
|
std::cout << "[测试] DispatchManager\n";
|
||||||
|
|
||||||
|
ocpm::DispatchManager dm;
|
||||||
|
dm.loadSampleData();
|
||||||
|
|
||||||
|
// 资产状态
|
||||||
|
assert(dm.getAssetStatus("ASSET-001") == ocpm::AssetStatusCode::READY);
|
||||||
|
assert(dm.getAssetStatus("ASSET-003") == ocpm::AssetStatusCode::FAULT);
|
||||||
|
assert(dm.getAssetStatus("UNKNOWN") == ocpm::AssetStatusCode::OFFLINE);
|
||||||
|
|
||||||
|
// 分发
|
||||||
|
int sent = dm.dispatchPlan("PLAN-001", {"ASSET-001", "ASSET-002", "ASSET-003"});
|
||||||
|
assert(sent == 1); // 只有 ASSET-001 是 READY
|
||||||
|
|
||||||
|
// 执行统计
|
||||||
|
auto stats = dm.getExecutionStats();
|
||||||
|
assert(stats.total_tasks == 5);
|
||||||
|
assert(stats.completed_tasks == 1);
|
||||||
|
assert(stats.remaining_time > 0.0);
|
||||||
|
|
||||||
|
// 仪表盘
|
||||||
|
auto dash = dm.getDashboardData();
|
||||||
|
assert(dash.execution.total_tasks == 5);
|
||||||
|
assert(dash.resource_rate > 0.0);
|
||||||
|
|
||||||
|
// 告警
|
||||||
|
auto alerts = dm.getAlerts();
|
||||||
|
assert(alerts.size() == 2);
|
||||||
|
|
||||||
|
// 按等级过滤告警
|
||||||
|
ocpm::AlertLevel err = ocpm::AlertLevel::ERROR;
|
||||||
|
auto err_alerts = dm.getAlerts(&err);
|
||||||
|
assert(err_alerts.size() == 1);
|
||||||
|
assert(err_alerts[0].code == 1002);
|
||||||
|
|
||||||
|
// 清除告警
|
||||||
|
dm.clearAlerts();
|
||||||
|
assert(dm.getAlerts().empty());
|
||||||
|
|
||||||
|
// 子任务流程图
|
||||||
|
auto tasks = dm.getTaskFlow();
|
||||||
|
assert(tasks.size() == 5);
|
||||||
|
assert(tasks[0].task_id == "TASK-01");
|
||||||
|
assert(tasks[1].dependency_ids.size() == 1);
|
||||||
|
assert(tasks[1].dependency_ids[0] == "TASK-01");
|
||||||
|
|
||||||
|
std::cout << " ✓ 所有 DispatchManager 测试通过\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 主测试入口
|
||||||
|
int main() {
|
||||||
|
std::cout << "========================================\n";
|
||||||
|
std::cout << " OCPM 单元测试\n";
|
||||||
|
std::cout << "========================================\n\n";
|
||||||
|
|
||||||
|
test_plan_manager();
|
||||||
|
test_distributed_plan_manager();
|
||||||
|
test_dispatch_manager();
|
||||||
|
|
||||||
|
std::cout << "\n========================================\n";
|
||||||
|
std::cout << " 所有测试通过!\n";
|
||||||
|
std::cout << "========================================\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue