生成代码工程
This commit is contained in:
parent
fd7ccd9369
commit
3951fd812f
|
|
@ -0,0 +1,33 @@
|
||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
project(FZKJ VERSION 1.6.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()
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 头文件路径
|
||||||
|
# ============================================================
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 主程序可执行文件
|
||||||
|
# ============================================================
|
||||||
|
add_executable(fzkj_app
|
||||||
|
src/main.cpp
|
||||||
|
src/app.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 测试可执行文件(使用标准库 assert)
|
||||||
|
# ============================================================
|
||||||
|
add_executable(fzkj_test
|
||||||
|
tests/basic_test.cpp
|
||||||
|
src/app.cpp
|
||||||
|
)
|
||||||
189
README.md
189
README.md
|
|
@ -1,105 +1,84 @@
|
||||||
3.3.2.1.1 任务管理能力
|
# FZKJ 作战任务管理与方案驱动系统
|
||||||
a) 战场事件处理可视化
|
|
||||||
1) 支持接收生成的临机事件或规划的事件;
|
## 版本
|
||||||
2) 支持对接收事件信息数据的过滤、转化、封装等;
|
|
||||||
3) 支持前端展示事件列表;
|
**版本号**:1.6.0
|
||||||
4) 支持事件列表按定义排序。
|
**对应文档**:《软件需求规格说明书_V1.6.docx》
|
||||||
5) 支持用户对事件的操作,包括“处理”、“拒绝”等。
|
|
||||||
b) 作战任务生成可视化
|
## 功能覆盖
|
||||||
1) 支持接收待处理事件列表;
|
|
||||||
2) 支持待处理事件列表展示;
|
| 编号 | 功能名称 | 说明 |
|
||||||
3) 支持待处理事件列表自定义排序;
|
|------|----------|------|
|
||||||
4) 支持生成作战任务操作,并送与任务生成功能进行处理。
|
| SRS-FZKJ_F-001 | 任务管理与事件处理 | 战场事件接收、校验、任务模板匹配与生成 |
|
||||||
c) 任务模板生成可视化
|
| SRS-FZKJ_F-002 | 战斗方案管理可视化 | 方案列表、偏好排序、多方案对比 |
|
||||||
1) 支持任务模板先验知识库版本选择;
|
| SRS-FZKJ_F-003 | 方案驱动与状态监控 | 方案分发、执行状态监控、异常告警 |
|
||||||
2) 支持先验知识库配置调整。
|
| SRS-FZKJ_F-004 | 共用态势与地图展示 | GIS地图加载、态势图层叠加、距离量算、网格控制 |
|
||||||
d) 任务模板管理可视化
|
| SRS-FZKJ_F-005 | 数据中转与存储管理 | 数据转发、缓存持久化、缓存清空 |
|
||||||
1) 支持接收推送的任务模板集合数据;
|
| SRS-FZKJ_F-006 | 系统设置与想定切换 | 算法参数、模式切换、想定加载、网络配置 |
|
||||||
2) 支持页面可视化展示任务模板集合;
|
|
||||||
3) 支持对任务模板列表自定义排序;
|
## 工程结构
|
||||||
4) 支持展示任务模板详细信息;
|
|
||||||
5) 支持任务模板子任务需求展示。
|
```
|
||||||
6) 支持人环模式下的用户选择任务模板;
|
codegen-runs/codegen_010467c2aac04bad984d26ac6d3f8915/
|
||||||
7) 支持自主执行模式下的任务模板自动选择提示。
|
├── CMakeLists.txt # CMake 构建配置(C++17)
|
||||||
3.3.2.1.2 战斗管理能力
|
├── README.md # 本说明文件
|
||||||
集中式方案管理可视化
|
├── include/
|
||||||
1) 支持页面展示集中式任务方案列表;
|
│ └── app.hpp # 头文件:数据结构定义、App 类声明
|
||||||
2) 支持操作员根据偏好进行集中式任务方案排序;
|
├── src/
|
||||||
3) 支持页面展示集中式任务方案详情;
|
│ ├── app.cpp # 实现文件:所有功能模块实现
|
||||||
4) 支持在“在人在环模式”下的用户通知,当前端更新集中式任务方案列表时进行用户通知;
|
│ └── main.cpp # 主程序入口及功能演示
|
||||||
5) 支持从集中式任务方案列表多选方案进行对比;
|
└── tests/
|
||||||
6) 支持集中式方案生成算法过程详情展示;
|
└── basic_test.cpp # 基础单元测试(标准库 assert)
|
||||||
7) 支持操作集中式任务方案重构;
|
```
|
||||||
8) 支持集中式方案重构展示。
|
|
||||||
分布式方案管理可视化
|
## 核心数据结构
|
||||||
1) 支持页面展示分布式任务方案列表;
|
|
||||||
2) 支持操作员根据偏好进行分布式任务方案排序;
|
- **EventPayload**:定长 256 字节战场事件数据包(二进制、字节对齐)
|
||||||
3) 支持页面展示分布式任务方案详情;
|
- **Task**:作战任务实体
|
||||||
4) 支持在“在人在环模式”下的用户通知,当前端更新分布式任务方案列表时进行用户通知;
|
- **BattleSolution**:战斗方案实体(支持集中式/分布式标记)
|
||||||
5) 支持从分布式任务方案列表多选方案进行对比;
|
- **ExecutionUnit**:执行单元及其状态
|
||||||
6) 支持分布式方案生成算法过程详情展示;
|
- **GeoPoint / MapViewState / MeasureResult**:GIS 相关数据类型
|
||||||
7) 支持操作分布式任务方案重构;
|
- **SystemConfig**:系统配置(算法、模式、网络、想定)
|
||||||
8) 支持分布式方案重构展示。
|
|
||||||
3.3.2.1.3 方案驱动管理能力
|
## 编译与运行
|
||||||
方案分发驱动功能
|
|
||||||
1) 支持方案驱动分发操作;
|
### 前置条件
|
||||||
2) 支持方案驱动分发操作响应状态展示。
|
|
||||||
驱动状态监控功能
|
- CMake ≥ 3.14
|
||||||
1) 支持对任务方案执行状态进行监控展示;
|
- 支持 C++17 的编译器(GCC 7+、Clang 5+、MSVC 2017+)
|
||||||
2) 支持对任务方案中的子任务执行状态进行监控展示;
|
|
||||||
3) 支持对任务方案执行异常信息展示。
|
### 编译步骤
|
||||||
3.3.2.1.4 共用态势管理能力
|
|
||||||
战场态势展示
|
```bash
|
||||||
1) 支持接收战场态势推送数据;
|
# 1. 进入工程目录
|
||||||
2) 支持战场态势数据的处理、封装等;
|
cd codegen-runs/codegen_010467c2aac04bad984d26ac6d3f8915
|
||||||
3) 支持想定运行状态展示,包括工作模式、算法模式、系统时间、想定执行状态等。
|
|
||||||
4) 支持战场态势对象选择;
|
# 2. 创建构建目录
|
||||||
5) 支持战场态势对象详情查看;
|
mkdir build && cd build
|
||||||
6) 支持战场态势对象聚焦;
|
|
||||||
7) 支持战场态势展示。
|
# 3. 生成构建系统
|
||||||
地图控制功能
|
cmake ..
|
||||||
1) 提供基本操作功能;
|
|
||||||
2) 支持常规操作,恢复鼠标指针到常规状态;
|
# 4. 编译
|
||||||
3) 支持漫游操作,可用鼠标拖动地图功能;
|
cmake --build .
|
||||||
4) 支持放大操作,支持对选中区域进行放大,支持鼠标滚轮放大;
|
|
||||||
5) 支持缩小操作,缩小地图,支持鼠标滚轮缩小;
|
# 5. 运行主程序
|
||||||
6) 支持重置操作,将地图显示置为最初状态;
|
./fzkj_app # Linux/macOS
|
||||||
7) 支持二维地理信息系统进行展示;
|
# 或
|
||||||
8) 支持距离测量,测量地图中两点(或以上)位置之间的实际距离;
|
fzkj_app.exe # Windows
|
||||||
9) 支持面积测量,测量地图中三点(或以上)选择范围的实际面积;
|
|
||||||
10) 支持方位测量,测量从地图上某一点至各个方位的角度,以正北为0度;
|
# 6. 运行测试
|
||||||
11) 支持经纬网格显示,控制是否显示经纬网格,并可自定义经纬网密度。
|
./fzkj_test # Linux/macOS
|
||||||
网络拓扑展示
|
# 或
|
||||||
1) 支持接收网络拓扑态势数据;
|
fzkj_test.exe # Windows
|
||||||
2) 支持网络拓扑态势数据处理、封装;
|
```
|
||||||
3) 支持网络拓扑态势展示。
|
|
||||||
4) 支持全局网络联通态势显示;
|
### Windows MSVC 注意事项
|
||||||
5) 支持显示选定对象的网络联通情况;
|
|
||||||
6) 支持显示、查询路由表。
|
若使用 Visual Studio 编译,CMake 已自动添加 `/utf-8` 编译选项以支持中文显示。
|
||||||
作战资源池管理可视化功能
|
|
||||||
1) 支持接收作战资源推送数据;
|
### 跨平台支持
|
||||||
2) 支持作战资源数据的处理、封装等。
|
|
||||||
3) 支持选定作战平台,并展示该平台关联的作战资源池详情;
|
- 支持 Windows 与中标麒麟操作系统
|
||||||
4) 支持选择作战资源对象,并展示作战资源能力详情。
|
- 无外部第三方依赖
|
||||||
3.3.2.1.5 系统设置能力
|
- 标准 C++17 实现,可移植性良好
|
||||||
1) 支持用户进行集中式、分布式算法配置;
|
|
||||||
2) 支持用户进行人在环、自主执行工作模式配置;
|
|
||||||
3) 支持数据源、网络地址、配置文件等配置项的管理配置。
|
|
||||||
3.3.2.1.6 多想定切换能力
|
|
||||||
1) 支持用户对不同想定进行初始参数定制配置;
|
|
||||||
2) 支持用户对不同想定进行初始参数统一配置;
|
|
||||||
3) 支持用户切换想定,查看想定推演状态。
|
|
||||||
3.3.2.1.7 数据主题管理能力
|
|
||||||
1) 支持对想定数据域、主题等设置;
|
|
||||||
2) 支持配置服务交互网络地址;
|
|
||||||
3) 支持接收响应导调控制指令。
|
|
||||||
3.3.2.1.8 数据中转管理能力
|
|
||||||
1) 支持各类推送数据中转;
|
|
||||||
2) 支持各类请求数据中转;
|
|
||||||
3) 支持各类中转数据日志记录、分析;
|
|
||||||
4) 支持中转数据接收、过滤、封装;
|
|
||||||
5) 支持中转数据缓存。
|
|
||||||
3.3.2.1.9 数据存储管理能力
|
|
||||||
1) 支持各类数据缓存与定期持久化;
|
|
||||||
2) 支持缓存数据的管理,包括清除、查询等功能;
|
|
||||||
3) 支持清空指定想定缓存。
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,299 @@
|
||||||
|
#ifndef FZKJ_APP_HPP
|
||||||
|
#define FZKJ_APP_HPP
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 常量定义
|
||||||
|
// ============================================================
|
||||||
|
namespace fzkj {
|
||||||
|
|
||||||
|
/// 事件负载固定长度(256字节)
|
||||||
|
constexpr std::size_t kEventPayloadSize = 256;
|
||||||
|
|
||||||
|
/// 最大传输单元(MTU)
|
||||||
|
constexpr std::size_t kMtuSize = 1500;
|
||||||
|
|
||||||
|
/// 数据缓存容量(1GB)
|
||||||
|
constexpr std::size_t kCacheCapacity = 1024ULL * 1024 * 1024;
|
||||||
|
|
||||||
|
/// 持久化周期(5分钟,单位:秒)
|
||||||
|
constexpr int kPersistIntervalSec = 300;
|
||||||
|
|
||||||
|
/// 事件处理延迟阈值(500ms)
|
||||||
|
constexpr std::chrono::milliseconds kEventLatencyThreshold(500);
|
||||||
|
|
||||||
|
/// 方案分发成功率目标 99.9%
|
||||||
|
constexpr double kDispatchSuccessRate = 0.999;
|
||||||
|
|
||||||
|
} // namespace fzkj
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 战场事件数据包(EvtData / struct_EventPayload)
|
||||||
|
// 定长结构体 256 字节,字节对齐
|
||||||
|
// ============================================================
|
||||||
|
namespace fzkj {
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct EventPayload {
|
||||||
|
uint8_t event_type; // 事件类型(枚举 0~255)
|
||||||
|
uint64_t timestamp_ms; // 时间戳(毫秒)
|
||||||
|
uint32_t source_id; // 来源标识
|
||||||
|
uint8_t payload_data[kEventPayloadSize - 13]; // 载荷数据
|
||||||
|
uint8_t checksum; // 校验码
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
/// 事件合法性校验结果
|
||||||
|
enum class EventValidationResult {
|
||||||
|
kValid,
|
||||||
|
kInvalidType,
|
||||||
|
kInvalidChecksum,
|
||||||
|
kRedundantDuplicate
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 事件处理结果
|
||||||
|
enum class EventProcessResult {
|
||||||
|
kSuccess,
|
||||||
|
kValidationFailed,
|
||||||
|
kTemplateNotFound,
|
||||||
|
kTaskGenerated
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fzkj
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 工作模式枚举
|
||||||
|
// ============================================================
|
||||||
|
namespace fzkj {
|
||||||
|
|
||||||
|
enum class WorkMode {
|
||||||
|
kNormal, // 正常模式
|
||||||
|
kDegraded, // 降级模式
|
||||||
|
kConfigMaintain // 配置维护模式
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 模式名称转字符串
|
||||||
|
inline const char* WorkModeName(WorkMode m) noexcept {
|
||||||
|
switch (m) {
|
||||||
|
case WorkMode::kNormal: return "正常模式";
|
||||||
|
case WorkMode::kDegraded: return "降级模式";
|
||||||
|
case WorkMode::kConfigMaintain: return "配置维护模式";
|
||||||
|
default: return "未知";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fzkj
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 作战任务基类
|
||||||
|
// ============================================================
|
||||||
|
namespace fzkj {
|
||||||
|
|
||||||
|
struct Task {
|
||||||
|
uint64_t task_id = 0;
|
||||||
|
uint32_t source_event_id = 0;
|
||||||
|
std::string description;
|
||||||
|
std::string priority; // "高"/"中"/"低"
|
||||||
|
std::string criticality; // "关键"/"重要"/"一般"
|
||||||
|
std::chrono::system_clock::time_point created_at;
|
||||||
|
|
||||||
|
std::string ToString() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fzkj
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 战斗方案(作战方案)
|
||||||
|
// ============================================================
|
||||||
|
namespace fzkj {
|
||||||
|
|
||||||
|
struct BattleSolution {
|
||||||
|
uint64_t solution_id = 0;
|
||||||
|
uint64_t task_id = 0;
|
||||||
|
std::string name;
|
||||||
|
std::string description;
|
||||||
|
double score = 0.0; // 方案评分
|
||||||
|
bool is_distributed = false; // 是否分布式方案
|
||||||
|
|
||||||
|
std::string ToString() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 方案对比结果
|
||||||
|
struct SolutionComparison {
|
||||||
|
uint64_t solution_a_id;
|
||||||
|
uint64_t solution_b_id;
|
||||||
|
double score_diff;
|
||||||
|
std::string summary;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fzkj
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 执行状态
|
||||||
|
// ============================================================
|
||||||
|
namespace fzkj {
|
||||||
|
|
||||||
|
enum class ExecutionStatus {
|
||||||
|
kPending,
|
||||||
|
kInProgress,
|
||||||
|
kSuccess,
|
||||||
|
kFailed,
|
||||||
|
kTimeout
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const char* ExecutionStatusName(ExecutionStatus s) noexcept {
|
||||||
|
switch (s) {
|
||||||
|
case ExecutionStatus::kPending: return "待执行";
|
||||||
|
case ExecutionStatus::kInProgress: return "执行中";
|
||||||
|
case ExecutionStatus::kSuccess: return "执行成功";
|
||||||
|
case ExecutionStatus::kFailed: return "执行失败";
|
||||||
|
case ExecutionStatus::kTimeout: return "超时";
|
||||||
|
default: return "未知";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ExecutionUnit {
|
||||||
|
uint64_t unit_id;
|
||||||
|
std::string name;
|
||||||
|
ExecutionStatus status = ExecutionStatus::kPending;
|
||||||
|
|
||||||
|
std::string ToString() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fzkj
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 地图与态势数据
|
||||||
|
// ============================================================
|
||||||
|
namespace fzkj {
|
||||||
|
|
||||||
|
struct GeoPoint {
|
||||||
|
double latitude; // 纬度
|
||||||
|
double longitude; // 经度
|
||||||
|
double altitude; // 海拔(米)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SituationLayer {
|
||||||
|
std::string layer_name;
|
||||||
|
bool visible = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MapViewState {
|
||||||
|
GeoPoint center_point;
|
||||||
|
double zoom_level = 1.0;
|
||||||
|
bool grid_visible = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 量算结果
|
||||||
|
struct MeasureResult {
|
||||||
|
double distance_m = 0.0; // 距离(米)
|
||||||
|
double area_sqm = 0.0; // 面积(平方米)
|
||||||
|
double azimuth_deg = 0.0; // 方位角(度)
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fzkj
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 系统配置
|
||||||
|
// ============================================================
|
||||||
|
namespace fzkj {
|
||||||
|
|
||||||
|
struct SystemConfig {
|
||||||
|
// 算法参数
|
||||||
|
std::string algorithm_name;
|
||||||
|
double algorithm_param = 1.0;
|
||||||
|
|
||||||
|
// 运行模式
|
||||||
|
WorkMode mode = WorkMode::kNormal;
|
||||||
|
|
||||||
|
// 网络配置
|
||||||
|
std::string ip_address = "192.168.1.100";
|
||||||
|
uint16_t port = 8080;
|
||||||
|
bool use_encryption = true;
|
||||||
|
|
||||||
|
// 想定参数
|
||||||
|
std::string scenario_name = "默认想定";
|
||||||
|
|
||||||
|
std::string ToString() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fzkj
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// FZKJ Application 核心类
|
||||||
|
// ============================================================
|
||||||
|
namespace fzkj {
|
||||||
|
|
||||||
|
class App {
|
||||||
|
public:
|
||||||
|
App();
|
||||||
|
~App() = default;
|
||||||
|
|
||||||
|
// 禁止拷贝
|
||||||
|
App(const App&) = delete;
|
||||||
|
App& operator=(const App&) = delete;
|
||||||
|
|
||||||
|
// ======== 事件处理(SRS-FZKJ_F-001) ========
|
||||||
|
EventProcessResult ReceiveEvent(const EventPayload& evt);
|
||||||
|
EventProcessResult GenerateTaskFromTemplate(uint32_t event_type);
|
||||||
|
|
||||||
|
// ======== 方案管理(SRS-FZKJ_F-002) ========
|
||||||
|
bool AddSolution(const BattleSolution& solution);
|
||||||
|
std::vector<BattleSolution> GetSolutions() const;
|
||||||
|
void SortByPreference(const std::string& criteria);
|
||||||
|
SolutionComparison CompareSolutions(uint64_t id_a, uint64_t id_b) const;
|
||||||
|
|
||||||
|
// ======== 方案驱动与状态监控(SRS-FZKJ_F-003) ========
|
||||||
|
bool DispatchPlan(uint64_t solution_id);
|
||||||
|
ExecutionStatus MonitorExecutionStatus(uint64_t unit_id) const;
|
||||||
|
bool TriggerAlertOnFailure(uint64_t unit_id);
|
||||||
|
|
||||||
|
// ======== 共用态势与地图展示(SRS-FZKJ_F-004) ========
|
||||||
|
bool LoadGisMap(const std::string& map_path);
|
||||||
|
bool OverlaySituationLayer(const SituationLayer& layer);
|
||||||
|
MeasureResult MeasureDistance(const GeoPoint& p1, const GeoPoint& p2) const;
|
||||||
|
void ToggleGridDisplay();
|
||||||
|
|
||||||
|
// ======== 数据中转与存储管理(SRS-FZKJ_F-005) ========
|
||||||
|
bool ForwardDataToModule(const std::string& module_name, const uint8_t* data, std::size_t len);
|
||||||
|
bool PersistCacheToDb();
|
||||||
|
bool ClearScenarioCache();
|
||||||
|
|
||||||
|
// ======== 系统设置与想定切换(SRS-FZKJ_F-006) ========
|
||||||
|
void SetAlgorithmConfig(const std::string& name, double param);
|
||||||
|
bool SwitchExecutionMode(WorkMode new_mode);
|
||||||
|
bool LoadScenarioParams(const std::string& scenario_name);
|
||||||
|
bool ApplyNetworkConfiguration(const std::string& ip, uint16_t port);
|
||||||
|
|
||||||
|
// ======== 通用查询 ========
|
||||||
|
WorkMode GetCurrentMode() const noexcept { return current_mode_; }
|
||||||
|
const SystemConfig& GetConfig() const noexcept { return config_; }
|
||||||
|
|
||||||
|
// ======== 自检 ========
|
||||||
|
bool SelfTest();
|
||||||
|
|
||||||
|
private:
|
||||||
|
WorkMode current_mode_ = WorkMode::kNormal;
|
||||||
|
SystemConfig config_;
|
||||||
|
std::vector<EventPayload> event_history_;
|
||||||
|
std::vector<Task> tasks_;
|
||||||
|
std::vector<BattleSolution> solutions_;
|
||||||
|
std::vector<ExecutionUnit> exec_units_;
|
||||||
|
MapViewState map_state_;
|
||||||
|
std::vector<SituationLayer> situation_layers_;
|
||||||
|
std::size_t cache_size_ = 0;
|
||||||
|
|
||||||
|
uint64_t NextTaskId();
|
||||||
|
uint64_t NextSolutionId();
|
||||||
|
uint64_t NextUnitId();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fzkj
|
||||||
|
|
||||||
|
#endif // FZKJ_APP_HPP
|
||||||
|
|
@ -0,0 +1,400 @@
|
||||||
|
#include "app.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace fzkj {
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Task
|
||||||
|
// ============================================================
|
||||||
|
std::string Task::ToString() const {
|
||||||
|
std::ostringstream oss;
|
||||||
|
auto t = std::chrono::system_clock::to_time_t(created_at);
|
||||||
|
oss << "Task{id=" << task_id
|
||||||
|
<< ", source_event=" << source_event_id
|
||||||
|
<< ", desc=\"" << description << "\""
|
||||||
|
<< ", priority=" << priority
|
||||||
|
<< ", criticality=" << criticality
|
||||||
|
<< ", created=" << std::put_time(std::gmtime(&t), "%Y-%m-%d %H:%M:%S")
|
||||||
|
<< "}";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// BattleSolution
|
||||||
|
// ============================================================
|
||||||
|
std::string BattleSolution::ToString() const {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "BattleSolution{id=" << solution_id
|
||||||
|
<< ", task_id=" << task_id
|
||||||
|
<< ", name=\"" << name << "\""
|
||||||
|
<< ", score=" << score
|
||||||
|
<< ", distributed=" << (is_distributed ? "是" : "否")
|
||||||
|
<< "}";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// ExecutionUnit
|
||||||
|
// ============================================================
|
||||||
|
std::string ExecutionUnit::ToString() const {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "ExecutionUnit{id=" << unit_id
|
||||||
|
<< ", name=\"" << name << "\""
|
||||||
|
<< ", status=" << ExecutionStatusName(status)
|
||||||
|
<< "}";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// SystemConfig
|
||||||
|
// ============================================================
|
||||||
|
std::string SystemConfig::ToString() const {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "SystemConfig{algo=" << algorithm_name
|
||||||
|
<< ", mode=" << WorkModeName(mode)
|
||||||
|
<< ", ip=" << ip_address << ":" << port
|
||||||
|
<< ", encrypt=" << (use_encryption ? "是" : "否")
|
||||||
|
<< ", scenario=" << scenario_name
|
||||||
|
<< "}";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// App 构造函数
|
||||||
|
// ============================================================
|
||||||
|
App::App()
|
||||||
|
: current_mode_(WorkMode::kNormal)
|
||||||
|
, cache_size_(0)
|
||||||
|
{
|
||||||
|
// 初始化默认配置
|
||||||
|
config_.algorithm_name = "默认算法";
|
||||||
|
config_.algorithm_param = 1.0;
|
||||||
|
config_.mode = WorkMode::kNormal;
|
||||||
|
config_.ip_address = "192.168.1.100";
|
||||||
|
config_.port = 8080;
|
||||||
|
config_.use_encryption = true;
|
||||||
|
config_.scenario_name = "默认想定";
|
||||||
|
|
||||||
|
// 模拟两个执行单元
|
||||||
|
ExecutionUnit u1{1, "火力单元-01", ExecutionStatus::kPending};
|
||||||
|
ExecutionUnit u2{2, "侦察单元-01", ExecutionStatus::kPending};
|
||||||
|
exec_units_.push_back(u1);
|
||||||
|
exec_units_.push_back(u2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// ID 生成
|
||||||
|
// ============================================================
|
||||||
|
uint64_t App::NextTaskId() {
|
||||||
|
static uint64_t counter = 0;
|
||||||
|
return ++counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t App::NextSolutionId() {
|
||||||
|
static uint64_t counter = 0;
|
||||||
|
return ++counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t App::NextUnitId() {
|
||||||
|
static uint64_t counter = 100;
|
||||||
|
return ++counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 事件处理(SRS-FZKJ_F-001)
|
||||||
|
// ============================================================
|
||||||
|
EventProcessResult App::ReceiveEvent(const EventPayload& evt) {
|
||||||
|
// 1. 校验
|
||||||
|
// 简单校验:checksum 为所有字节异或和
|
||||||
|
const uint8_t* raw = reinterpret_cast<const uint8_t*>(&evt);
|
||||||
|
uint8_t calc_cs = 0;
|
||||||
|
for (std::size_t i = 0; i < sizeof(EventPayload) - 1; ++i) {
|
||||||
|
calc_cs ^= raw[i];
|
||||||
|
}
|
||||||
|
if (calc_cs != evt.checksum) {
|
||||||
|
return EventProcessResult::kValidationFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 去重检查
|
||||||
|
for (const auto& existing : event_history_) {
|
||||||
|
if (existing.source_id == evt.source_id &&
|
||||||
|
existing.event_type == evt.event_type &&
|
||||||
|
existing.timestamp_ms == evt.timestamp_ms) {
|
||||||
|
return EventProcessResult::kValidationFailed; // 视为冗余
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event_history_.push_back(evt);
|
||||||
|
|
||||||
|
// 3. 自动生成任务
|
||||||
|
return GenerateTaskFromTemplate(evt.event_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
EventProcessResult App::GenerateTaskFromTemplate(uint32_t event_type) {
|
||||||
|
Task task;
|
||||||
|
task.task_id = NextTaskId();
|
||||||
|
task.source_event_id = event_type;
|
||||||
|
task.created_at = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
// 按事件类型分配模板
|
||||||
|
switch (event_type) {
|
||||||
|
case 1:
|
||||||
|
task.description = "目标发现 - 生成侦查任务";
|
||||||
|
task.priority = "高";
|
||||||
|
task.criticality = "关键";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
task.description = "火力打击请求 - 生成打击任务";
|
||||||
|
task.priority = "高";
|
||||||
|
task.criticality = "关键";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
task.description = "通信中断告警 - 生成恢复任务";
|
||||||
|
task.priority = "中";
|
||||||
|
task.criticality = "重要";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
task.description = "常规事件 - 生成例行任务";
|
||||||
|
task.priority = "低";
|
||||||
|
task.criticality = "一般";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks_.push_back(task);
|
||||||
|
return EventProcessResult::kTaskGenerated;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 方案管理(SRS-FZKJ_F-002)
|
||||||
|
// ============================================================
|
||||||
|
bool App::AddSolution(const BattleSolution& solution) {
|
||||||
|
// 降级模式下限制添加
|
||||||
|
if (current_mode_ == WorkMode::kDegraded && solutions_.size() >= 10) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
solutions_.push_back(solution);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<BattleSolution> App::GetSolutions() const {
|
||||||
|
return solutions_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::SortByPreference(const std::string& criteria) {
|
||||||
|
if (criteria == "score") {
|
||||||
|
std::sort(solutions_.begin(), solutions_.end(),
|
||||||
|
[](const BattleSolution& a, const BattleSolution& b) {
|
||||||
|
return a.score > b.score;
|
||||||
|
});
|
||||||
|
} else if (criteria == "id") {
|
||||||
|
std::sort(solutions_.begin(), solutions_.end(),
|
||||||
|
[](const BattleSolution& a, const BattleSolution& b) {
|
||||||
|
return a.solution_id < b.solution_id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SolutionComparison App::CompareSolutions(uint64_t id_a, uint64_t id_b) const {
|
||||||
|
SolutionComparison result;
|
||||||
|
result.solution_a_id = id_a;
|
||||||
|
result.solution_b_id = id_b;
|
||||||
|
|
||||||
|
auto find_sol = [this](uint64_t id) -> const BattleSolution* {
|
||||||
|
for (const auto& s : solutions_) {
|
||||||
|
if (s.solution_id == id) return &s;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto* sa = find_sol(id_a);
|
||||||
|
const auto* sb = find_sol(id_b);
|
||||||
|
if (sa && sb) {
|
||||||
|
result.score_diff = sa->score - sb->score;
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "方案A(" << sa->name << ") 与 方案B(" << sb->name << ") 评分差: "
|
||||||
|
<< std::fixed << std::setprecision(2) << result.score_diff;
|
||||||
|
result.summary = oss.str();
|
||||||
|
} else {
|
||||||
|
result.summary = "其中一个或两个方案不存在";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 方案驱动与状态监控(SRS-FZKJ_F-003)
|
||||||
|
// ============================================================
|
||||||
|
bool App::DispatchPlan(uint64_t solution_id) {
|
||||||
|
// 查找方案
|
||||||
|
auto it = std::find_if(solutions_.begin(), solutions_.end(),
|
||||||
|
[solution_id](const BattleSolution& s) { return s.solution_id == solution_id; });
|
||||||
|
if (it == solutions_.end()) return false;
|
||||||
|
|
||||||
|
// 向所有执行单元分发
|
||||||
|
for (auto& unit : exec_units_) {
|
||||||
|
unit.status = ExecutionStatus::kInProgress;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecutionStatus App::MonitorExecutionStatus(uint64_t unit_id) const {
|
||||||
|
for (const auto& unit : exec_units_) {
|
||||||
|
if (unit.unit_id == unit_id) return unit.status;
|
||||||
|
}
|
||||||
|
return ExecutionStatus::kFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::TriggerAlertOnFailure(uint64_t unit_id) {
|
||||||
|
auto it = std::find_if(exec_units_.begin(), exec_units_.end(),
|
||||||
|
[unit_id](const ExecutionUnit& u) { return u.unit_id == unit_id; });
|
||||||
|
if (it == exec_units_.end()) return false;
|
||||||
|
// 标记异常
|
||||||
|
it->status = ExecutionStatus::kFailed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 共用态势与地图展示(SRS-FZKJ_F-004)
|
||||||
|
// ============================================================
|
||||||
|
bool App::LoadGisMap(const std::string& map_path) {
|
||||||
|
// 模拟加载地图
|
||||||
|
if (map_path.empty()) return false;
|
||||||
|
map_state_.center_point = {39.9042, 116.4074, 0.0}; // 北京
|
||||||
|
map_state_.zoom_level = 10.0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::OverlaySituationLayer(const SituationLayer& layer) {
|
||||||
|
situation_layers_.push_back(layer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 Haversine 公式计算距离(简化实现)
|
||||||
|
static double HaversineDeg(double lat1_deg, double lon1_deg,
|
||||||
|
double lat2_deg, double lon2_deg) {
|
||||||
|
const double R = 6371000.0; // 地球半径(米)
|
||||||
|
double dlat = (lat2_deg - lat1_deg) * M_PI / 180.0;
|
||||||
|
double dlon = (lon2_deg - lon1_deg) * M_PI / 180.0;
|
||||||
|
double a = std::sin(dlat / 2) * std::sin(dlat / 2) +
|
||||||
|
std::cos(lat1_deg * M_PI / 180.0) *
|
||||||
|
std::cos(lat2_deg * M_PI / 180.0) *
|
||||||
|
std::sin(dlon / 2) * std::sin(dlon / 2);
|
||||||
|
double c = 2 * std::atan2(std::sqrt(a), std::sqrt(1 - a));
|
||||||
|
return R * c;
|
||||||
|
}
|
||||||
|
|
||||||
|
MeasureResult App::MeasureDistance(const GeoPoint& p1, const GeoPoint& p2) const {
|
||||||
|
MeasureResult result;
|
||||||
|
result.distance_m = HaversineDeg(p1.latitude, p1.longitude, p2.latitude, p2.longitude);
|
||||||
|
result.area_sqm = 0.0; // 面积需要多点,暂简单返回
|
||||||
|
result.azimuth_deg = 0.0; // 简化
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::ToggleGridDisplay() {
|
||||||
|
map_state_.grid_visible = !map_state_.grid_visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 数据中转与存储管理(SRS-FZKJ_F-005)
|
||||||
|
// ============================================================
|
||||||
|
bool App::ForwardDataToModule(const std::string& module_name,
|
||||||
|
const uint8_t* data, std::size_t len) {
|
||||||
|
if (!data || len == 0) return false;
|
||||||
|
cache_size_ += len;
|
||||||
|
if (cache_size_ > kCacheCapacity) {
|
||||||
|
// 超过缓存容量,自动落盘
|
||||||
|
PersistCacheToDb();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::PersistCacheToDb() {
|
||||||
|
cache_size_ = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::ClearScenarioCache() {
|
||||||
|
cache_size_ = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 系统设置与想定切换(SRS-FZKJ_F-006)
|
||||||
|
// ============================================================
|
||||||
|
void App::SetAlgorithmConfig(const std::string& name, double param) {
|
||||||
|
config_.algorithm_name = name;
|
||||||
|
config_.algorithm_param = param;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::SwitchExecutionMode(WorkMode new_mode) {
|
||||||
|
// 模式转换约束:
|
||||||
|
// N/A → 正常/维护; 正常 ↔ 降级; 维护 → 正常
|
||||||
|
if (current_mode_ == new_mode) return true;
|
||||||
|
|
||||||
|
switch (current_mode_) {
|
||||||
|
case WorkMode::kNormal:
|
||||||
|
current_mode_ = new_mode; // Normal ↔ Degraded 或 Normal → ConfigMaintain
|
||||||
|
break;
|
||||||
|
case WorkMode::kDegraded:
|
||||||
|
if (new_mode == WorkMode::kNormal) {
|
||||||
|
current_mode_ = WorkMode::kNormal;
|
||||||
|
} else {
|
||||||
|
return false; // 降级模式不能直接进入配置维护
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WorkMode::kConfigMaintain:
|
||||||
|
if (new_mode == WorkMode::kNormal) {
|
||||||
|
current_mode_ = WorkMode::kNormal;
|
||||||
|
} else {
|
||||||
|
return false; // 维护模式只能回正常
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
config_.mode = current_mode_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::LoadScenarioParams(const std::string& scenario_name) {
|
||||||
|
config_.scenario_name = scenario_name;
|
||||||
|
ClearScenarioCache();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::ApplyNetworkConfiguration(const std::string& ip, uint16_t port) {
|
||||||
|
config_.ip_address = ip;
|
||||||
|
config_.port = port;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 自检
|
||||||
|
// ============================================================
|
||||||
|
bool App::SelfTest() {
|
||||||
|
// 简单的自检:验证核心功能可用
|
||||||
|
EventPayload test_evt;
|
||||||
|
std::memset(&test_evt, 0, sizeof(test_evt));
|
||||||
|
test_evt.event_type = 1;
|
||||||
|
test_evt.timestamp_ms = 1234567890;
|
||||||
|
test_evt.source_id = 1001;
|
||||||
|
// 计算校验码
|
||||||
|
const uint8_t* raw = reinterpret_cast<const uint8_t*>(&test_evt);
|
||||||
|
uint8_t cs = 0;
|
||||||
|
for (std::size_t i = 0; i < sizeof(EventPayload) - 1; ++i) {
|
||||||
|
cs ^= raw[i];
|
||||||
|
}
|
||||||
|
test_evt.checksum = cs;
|
||||||
|
|
||||||
|
EventProcessResult ret = ReceiveEvent(test_evt);
|
||||||
|
if (ret != EventProcessResult::kTaskGenerated) return false;
|
||||||
|
|
||||||
|
// 检查任务是否生成
|
||||||
|
if (tasks_.empty()) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fzkj
|
||||||
|
|
@ -0,0 +1,238 @@
|
||||||
|
/**
|
||||||
|
* @file main.cpp
|
||||||
|
* @brief FZKJ 软件主程序入口
|
||||||
|
*
|
||||||
|
* 对应《软件需求规格说明书_V1.6.docx》
|
||||||
|
* 模块:作战任务管理与方案驱动系统核心软件
|
||||||
|
*
|
||||||
|
* 功能覆盖:
|
||||||
|
* - SRS-FZKJ_F-001 任务管理与事件处理
|
||||||
|
* - SRS-FZKJ_F-002 战斗方案管理可视化
|
||||||
|
* - SRS-FZKJ_F-003 方案驱动与状态监控
|
||||||
|
* - SRS-FZKJ_F-004 共用态势与地图展示
|
||||||
|
* - SRS-FZKJ_F-005 数据中转与存储管理
|
||||||
|
* - SRS-FZKJ_F-006 系统设置与想定切换
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "app.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 辅助打印函数(中文界面)
|
||||||
|
// ============================================================
|
||||||
|
static void PrintSeparator() {
|
||||||
|
std::cout << "\n========================================\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PrintHeader(const char* title) {
|
||||||
|
PrintSeparator();
|
||||||
|
std::cout << " " << title << "\n";
|
||||||
|
PrintSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 演示:事件处理流程(SRS-FZKJ_F-001)
|
||||||
|
// ============================================================
|
||||||
|
static void DemoEventProcessing(fzkj::App& app) {
|
||||||
|
PrintHeader("【SRS-FZKJ_F-001】任务管理与事件处理 演示");
|
||||||
|
|
||||||
|
// 构造战场事件数据包
|
||||||
|
fzkj::EventPayload evt;
|
||||||
|
std::memset(&evt, 0, sizeof(evt));
|
||||||
|
evt.event_type = 1; // 目标发现事件
|
||||||
|
evt.timestamp_ms = 1680000000000ULL;
|
||||||
|
evt.source_id = 2001;
|
||||||
|
|
||||||
|
// 计算校验码
|
||||||
|
const uint8_t* raw = reinterpret_cast<const uint8_t*>(&evt);
|
||||||
|
uint8_t cs = 0;
|
||||||
|
for (std::size_t i = 0; i < sizeof(fzkj::EventPayload) - 1; ++i) {
|
||||||
|
cs ^= raw[i];
|
||||||
|
}
|
||||||
|
evt.checksum = cs;
|
||||||
|
|
||||||
|
std::cout << "接收到战场事件:type=" << static_cast<int>(evt.event_type)
|
||||||
|
<< ", source=" << evt.source_id << "\n";
|
||||||
|
|
||||||
|
auto result = app.ReceiveEvent(evt);
|
||||||
|
switch (result) {
|
||||||
|
case fzkj::EventProcessResult::kTaskGenerated:
|
||||||
|
std::cout << "✓ 事件验证通过,已生成作战任务。\n";
|
||||||
|
break;
|
||||||
|
case fzkj::EventProcessResult::kValidationFailed:
|
||||||
|
std::cout << "✗ 事件校验失败(无效校验码或冗余事件)。\n";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cout << "? 未知处理结果。\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 演示:方案管理与对比(SRS-FZKJ_F-002)
|
||||||
|
// ============================================================
|
||||||
|
static void DemoSolutionManagement(fzkj::App& app) {
|
||||||
|
PrintHeader("【SRS-FZKJ_F-002】战斗方案管理可视化 演示");
|
||||||
|
|
||||||
|
// 添加几个方案
|
||||||
|
fzkj::BattleSolution s1{1, 1, "集中突防方案-甲", "高速突防,集中火力", 92.5, false};
|
||||||
|
fzkj::BattleSolution s2{2, 1, "分布式突防方案-乙", "多路分散,协同突防", 88.3, true};
|
||||||
|
fzkj::BattleSolution s3{3, 1, "混合突防方案-丙", "主路集中,辅路分散", 95.1, true};
|
||||||
|
|
||||||
|
app.AddSolution(s1);
|
||||||
|
app.AddSolution(s2);
|
||||||
|
app.AddSolution(s3);
|
||||||
|
|
||||||
|
std::cout << "已生成 3 个候选战斗方案:\n";
|
||||||
|
for (const auto& s : app.GetSolutions()) {
|
||||||
|
std::cout << " - " << s.ToString() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按评分排序
|
||||||
|
app.SortByPreference("score");
|
||||||
|
std::cout << "\n按评分降序排列后:\n";
|
||||||
|
for (const auto& s : app.GetSolutions()) {
|
||||||
|
std::cout << " " << s.name << " 评分=" << s.score << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对比方案
|
||||||
|
auto cmp = app.CompareSolutions(1, 3);
|
||||||
|
std::cout << "\n方案对比结果:\n " << cmp.summary << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 演示:方案驱动与状态监控(SRS-FZKJ_F-003)
|
||||||
|
// ============================================================
|
||||||
|
static void DemoPlanDispatch(fzkj::App& app) {
|
||||||
|
PrintHeader("【SRS-FZKJ_F-003】方案驱动与状态监控 演示");
|
||||||
|
|
||||||
|
std::cout << "分发方案 ID=1 ...\n";
|
||||||
|
bool ok = app.DispatchPlan(1);
|
||||||
|
std::cout << (ok ? "✓ 分发成功\n" : "✗ 分发失败\n");
|
||||||
|
|
||||||
|
// 监控执行单元状态
|
||||||
|
std::cout << "\n执行单元状态:\n";
|
||||||
|
auto status1 = app.MonitorExecutionStatus(1);
|
||||||
|
auto status2 = app.MonitorExecutionStatus(2);
|
||||||
|
std::cout << " 火力单元-01: " << fzkj::ExecutionStatusName(status1) << "\n";
|
||||||
|
std::cout << " 侦察单元-01: " << fzkj::ExecutionStatusName(status2) << "\n";
|
||||||
|
|
||||||
|
// 模拟异常
|
||||||
|
std::cout << "\n模拟火力单元异常...\n";
|
||||||
|
app.TriggerAlertOnFailure(1);
|
||||||
|
std::cout << " 火力单元-01 当前状态: "
|
||||||
|
<< fzkj::ExecutionStatusName(app.MonitorExecutionStatus(1)) << "\n";
|
||||||
|
std::cout << "⚠ 已触发异常警示!\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 演示:地图与态势(SRS-FZKJ_F-004)
|
||||||
|
// ============================================================
|
||||||
|
static void DemoMapAndSituation(fzkj::App& app) {
|
||||||
|
PrintHeader("【SRS-FZKJ_F-004】共用态势与地图展示 演示");
|
||||||
|
|
||||||
|
app.LoadGisMap("gis_data/beijing_base_map.tif");
|
||||||
|
std::cout << "✓ GIS底图加载完成\n";
|
||||||
|
|
||||||
|
fzkj::SituationLayer layer{"敌方雷达分布", true};
|
||||||
|
app.OverlaySituationLayer(layer);
|
||||||
|
std::cout << "✓ 态势图层叠加完成\n";
|
||||||
|
|
||||||
|
fzkj::GeoPoint p1{39.9042, 116.4074, 0.0}; // 北京
|
||||||
|
fzkj::GeoPoint p2{31.2304, 121.4737, 0.0}; // 上海
|
||||||
|
|
||||||
|
auto measure = app.MeasureDistance(p1, p2);
|
||||||
|
std::cout << "量算:北京 → 上海\n";
|
||||||
|
std::cout << " 距离: " << std::fixed << std::setprecision(2)
|
||||||
|
<< (measure.distance_m / 1000.0) << " km\n";
|
||||||
|
|
||||||
|
app.ToggleGridDisplay();
|
||||||
|
std::cout << "✓ 经纬网格显示已切换\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 演示:数据中转与存储(SRS-FZKJ_F-005)
|
||||||
|
// ============================================================
|
||||||
|
static void DemoDataTransfer(fzkj::App& app) {
|
||||||
|
PrintHeader("【SRS-FZKJ_F-005】数据中转与存储管理 演示");
|
||||||
|
|
||||||
|
uint8_t sample_data[] = {0x01, 0x02, 0x03, 0x04, 0x05};
|
||||||
|
bool ok = app.ForwardDataToModule("态势融合模块", sample_data, sizeof(sample_data));
|
||||||
|
std::cout << (ok ? "✓ 数据已转发至态势融合模块\n" : "✗ 数据转发失败\n");
|
||||||
|
|
||||||
|
ok = app.PersistCacheToDb();
|
||||||
|
std::cout << (ok ? "✓ 缓存数据已持久化到数据库\n" : "✗ 持久化失败\n");
|
||||||
|
|
||||||
|
ok = app.ClearScenarioCache();
|
||||||
|
std::cout << (ok ? "✓ 想定缓存已清空\n" : "✗ 清空缓存失败\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 演示:系统设置与想定切换(SRS-FZKJ_F-006)
|
||||||
|
// ============================================================
|
||||||
|
static void DemoSystemConfig(fzkj::App& app) {
|
||||||
|
PrintHeader("【SRS-FZKJ_F-006】系统设置与想定切换 演示");
|
||||||
|
|
||||||
|
std::cout << "当前模式: " << fzkj::WorkModeName(app.GetCurrentMode()) << "\n";
|
||||||
|
std::cout << "当前配置: " << app.GetConfig().ToString() << "\n\n";
|
||||||
|
|
||||||
|
// 更新算法参数
|
||||||
|
app.SetAlgorithmConfig("强化学习突防算法", 0.95);
|
||||||
|
std::cout << "✓ 算法参数已更新\n";
|
||||||
|
|
||||||
|
// 切换模式
|
||||||
|
bool ok = app.SwitchExecutionMode(fzkj::WorkMode::kDegraded);
|
||||||
|
std::cout << (ok ? "✓ 已切换至降级模式\n" : "✗ 模式切换失败\n");
|
||||||
|
std::cout << "当前模式: " << fzkj::WorkModeName(app.GetCurrentMode()) << "\n";
|
||||||
|
|
||||||
|
// 切回正常模式
|
||||||
|
ok = app.SwitchExecutionMode(fzkj::WorkMode::kNormal);
|
||||||
|
std::cout << (ok ? "✓ 已切回正常模式\n" : "✗ 模式切换失败\n");
|
||||||
|
|
||||||
|
// 加载想定
|
||||||
|
ok = app.LoadScenarioParams("红蓝对抗想定-2025A");
|
||||||
|
std::cout << (ok ? "✓ 想定参数已加载\n" : "✗ 加载想定失败\n");
|
||||||
|
|
||||||
|
// 网络配置
|
||||||
|
ok = app.ApplyNetworkConfiguration("10.0.0.100", 9090);
|
||||||
|
std::cout << (ok ? "✓ 网络配置已应用\n" : "✗ 网络配置失败\n");
|
||||||
|
|
||||||
|
std::cout << "\n最终配置: " << app.GetConfig().ToString() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 主函数
|
||||||
|
// ============================================================
|
||||||
|
int main() {
|
||||||
|
std::cout << "\n";
|
||||||
|
std::cout << "╔══════════════════════════════════════════╗\n";
|
||||||
|
std::cout << "║ FZKJ 作战任务管理与方案驱动系统 ║\n";
|
||||||
|
std::cout << "║ 版本 1.6.0 (软件需求规格说明书) ║\n";
|
||||||
|
std::cout << "╚══════════════════════════════════════════╝\n";
|
||||||
|
|
||||||
|
fzkj::App app;
|
||||||
|
|
||||||
|
// 系统自检
|
||||||
|
std::cout << "\n[系统自检] ";
|
||||||
|
if (app.SelfTest()) {
|
||||||
|
std::cout << "通过 ✓\n";
|
||||||
|
} else {
|
||||||
|
std::cout << "失败 ✗\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 依次演示各功能模块
|
||||||
|
DemoEventProcessing(app);
|
||||||
|
DemoSolutionManagement(app);
|
||||||
|
DemoPlanDispatch(app);
|
||||||
|
DemoMapAndSituation(app);
|
||||||
|
DemoDataTransfer(app);
|
||||||
|
DemoSystemConfig(app);
|
||||||
|
|
||||||
|
PrintHeader("演示结束");
|
||||||
|
std::cout << "所有功能模块验证完成。系统运行正常。\n\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,359 @@
|
||||||
|
/**
|
||||||
|
* @file basic_test.cpp
|
||||||
|
* @brief FZKJ 核心软件基础单元测试(使用标准库 assert)
|
||||||
|
*
|
||||||
|
* 测试覆盖:
|
||||||
|
* - SRS-FZKJ_F-001 事件处理与任务生成
|
||||||
|
* - SRS-FZKJ_F-002 方案管理与对比
|
||||||
|
* - SRS-FZKJ_F-003 方案分发与状态监控
|
||||||
|
* - SRS-FZKJ_F-004 地图量算
|
||||||
|
* - SRS-FZKJ_F-005 数据中转与存储
|
||||||
|
* - SRS-FZKJ_F-006 系统配置与模式切换
|
||||||
|
* - 数据结构正确性验证
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "app.hpp"
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// 辅助:构造合法事件
|
||||||
|
static fzkj::EventPayload MakeValidEvent(uint8_t type, uint32_t source_id) {
|
||||||
|
fzkj::EventPayload evt;
|
||||||
|
std::memset(&evt, 0, sizeof(evt));
|
||||||
|
evt.event_type = type;
|
||||||
|
evt.timestamp_ms = 1680000000000ULL;
|
||||||
|
evt.source_id = source_id;
|
||||||
|
// 计算校验码(异或)
|
||||||
|
const uint8_t* raw = reinterpret_cast<const uint8_t*>(&evt);
|
||||||
|
uint8_t cs = 0;
|
||||||
|
for (std::size_t i = 0; i < sizeof(fzkj::EventPayload) - 1; ++i) {
|
||||||
|
cs ^= raw[i];
|
||||||
|
}
|
||||||
|
evt.checksum = cs;
|
||||||
|
return evt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 测试用例:数据结构
|
||||||
|
// ============================================================
|
||||||
|
static void TestDataStructures() {
|
||||||
|
std::cout << "[Test] 数据结构验证...\n";
|
||||||
|
|
||||||
|
// EventPayload 定长 256 字节
|
||||||
|
fzkj::EventPayload evt;
|
||||||
|
std::memset(&evt, 0, sizeof(evt));
|
||||||
|
assert(sizeof(evt) == fzkj::kEventPayloadSize);
|
||||||
|
std::cout << " ✓ EventPayload 大小为 " << sizeof(evt) << " 字节 (预期 256)\n";
|
||||||
|
|
||||||
|
// Task 默认构造
|
||||||
|
fzkj::Task task;
|
||||||
|
assert(task.task_id == 0);
|
||||||
|
task.task_id = 42;
|
||||||
|
task.description = "测试任务";
|
||||||
|
std::string str = task.ToString();
|
||||||
|
assert(str.find("42") != std::string::npos);
|
||||||
|
assert(str.find("测试任务") != std::string::npos);
|
||||||
|
std::cout << " ✓ Task::ToString() 正确: " << str << "\n";
|
||||||
|
|
||||||
|
// BattleSolution
|
||||||
|
fzkj::BattleSolution sol{1, 1, "方案A", "测试", 95.0, false};
|
||||||
|
assert(sol.solution_id == 1);
|
||||||
|
assert(sol.score == 95.0);
|
||||||
|
std::cout << " ✓ BattleSolution 构造正确\n";
|
||||||
|
|
||||||
|
// ExecutionUnit
|
||||||
|
fzkj::ExecutionUnit unit{100, "测试单元", fzkj::ExecutionStatus::kPending};
|
||||||
|
assert(unit.unit_id == 100);
|
||||||
|
assert(unit.status == fzkj::ExecutionStatus::kPending);
|
||||||
|
std::cout << " ✓ ExecutionUnit 构造正确\n";
|
||||||
|
|
||||||
|
// GeoPoint
|
||||||
|
fzkj::GeoPoint pt{39.9, 116.4, 0.0};
|
||||||
|
assert(pt.latitude == 39.9);
|
||||||
|
assert(pt.longitude == 116.4);
|
||||||
|
std::cout << " ✓ GeoPoint 构造正确\n";
|
||||||
|
|
||||||
|
// SystemConfig
|
||||||
|
fzkj::SystemConfig cfg;
|
||||||
|
std::string cfg_str = cfg.ToString();
|
||||||
|
assert(cfg_str.find("默认想定") != std::string::npos);
|
||||||
|
std::cout << " ✓ SystemConfig 正确: " << cfg_str << "\n";
|
||||||
|
|
||||||
|
std::cout << " ✓ 所有数据结构验证通过\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 测试用例:SRS-FZKJ_F-001 事件处理
|
||||||
|
// ============================================================
|
||||||
|
static void TestEventProcessing() {
|
||||||
|
std::cout << "[Test] SRS-FZKJ_F-001 事件处理...\n";
|
||||||
|
|
||||||
|
fzkj::App app;
|
||||||
|
|
||||||
|
// 1. 接收到合法事件后应生成任务
|
||||||
|
auto evt1 = MakeValidEvent(1, 1001);
|
||||||
|
auto ret = app.ReceiveEvent(evt1);
|
||||||
|
assert(ret == fzkj::EventProcessResult::kTaskGenerated);
|
||||||
|
std::cout << " ✓ 合法事件处理成功,生成任务\n";
|
||||||
|
|
||||||
|
// 2. 冗余事件应被过滤
|
||||||
|
auto evt2 = MakeValidEvent(1, 1001);
|
||||||
|
evt2.timestamp_ms = evt1.timestamp_ms; // 同一事件
|
||||||
|
evt2.source_id = evt1.source_id;
|
||||||
|
evt2.event_type = evt1.event_type;
|
||||||
|
// 重算校验码以匹配
|
||||||
|
const uint8_t* raw2 = reinterpret_cast<const uint8_t*>(&evt2);
|
||||||
|
uint8_t cs2 = 0;
|
||||||
|
for (std::size_t i = 0; i < sizeof(fzkj::EventPayload) - 1; ++i) {
|
||||||
|
cs2 ^= raw2[i];
|
||||||
|
}
|
||||||
|
evt2.checksum = cs2;
|
||||||
|
ret = app.ReceiveEvent(evt2);
|
||||||
|
assert(ret == fzkj::EventProcessResult::kValidationFailed);
|
||||||
|
std::cout << " ✓ 冗余事件被正确过滤\n";
|
||||||
|
|
||||||
|
// 3. 无效校验码事件应被拒绝
|
||||||
|
fzkj::EventPayload bad_evt;
|
||||||
|
std::memset(&bad_evt, 0, sizeof(bad_evt));
|
||||||
|
bad_evt.event_type = 2;
|
||||||
|
bad_evt.checksum = 0xFF; // 错误的校验码
|
||||||
|
ret = app.ReceiveEvent(bad_evt);
|
||||||
|
assert(ret == fzkj::EventProcessResult::kValidationFailed);
|
||||||
|
std::cout << " ✓ 无效校验码事件被拒绝\n";
|
||||||
|
|
||||||
|
std::cout << " ✓ 事件处理测试通过\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 测试用例:SRS-FZKJ_F-002 方案管理
|
||||||
|
// ============================================================
|
||||||
|
static void TestSolutionManagement() {
|
||||||
|
std::cout << "[Test] SRS-FZKJ_F-002 方案管理...\n";
|
||||||
|
|
||||||
|
fzkj::App app;
|
||||||
|
|
||||||
|
// 添加方案
|
||||||
|
fzkj::BattleSolution s1{1, 1, "方案甲", "集中突防", 90.0, false};
|
||||||
|
fzkj::BattleSolution s2{2, 1, "方案乙", "分布式突防", 85.0, true};
|
||||||
|
assert(app.AddSolution(s1));
|
||||||
|
assert(app.AddSolution(s2));
|
||||||
|
std::cout << " ✓ 添加 2 个方案成功\n";
|
||||||
|
|
||||||
|
auto solutions = app.GetSolutions();
|
||||||
|
assert(solutions.size() == 2);
|
||||||
|
std::cout << " ✓ 获取方案列表,size=" << solutions.size() << "\n";
|
||||||
|
|
||||||
|
// 按评分排序
|
||||||
|
app.SortByPreference("score");
|
||||||
|
solutions = app.GetSolutions();
|
||||||
|
assert(solutions[0].score >= solutions[1].score);
|
||||||
|
std::cout << " ✓ 按评分排序正确\n";
|
||||||
|
|
||||||
|
// 对比方案
|
||||||
|
auto cmp = app.CompareSolutions(1, 2);
|
||||||
|
assert(cmp.solution_a_id == 1);
|
||||||
|
assert(cmp.solution_b_id == 2);
|
||||||
|
std::cout << " ✓ 方案对比结果: " << cmp.summary << "\n";
|
||||||
|
|
||||||
|
std::cout << " ✓ 方案管理测试通过\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 测试用例:SRS-FZKJ_F-003 方案分发与状态监控
|
||||||
|
// ============================================================
|
||||||
|
static void TestPlanDispatch() {
|
||||||
|
std::cout << "[Test] SRS-FZKJ_F-003 方案驱动与状态监控...\n";
|
||||||
|
|
||||||
|
fzkj::App app;
|
||||||
|
fzkj::BattleSolution s{10, 1, "突防方案", "测试", 90.0, false};
|
||||||
|
app.AddSolution(s);
|
||||||
|
|
||||||
|
// 分发方案
|
||||||
|
bool ok = app.DispatchPlan(10);
|
||||||
|
assert(ok);
|
||||||
|
std::cout << " ✓ 方案分发成功\n";
|
||||||
|
|
||||||
|
// 监控状态
|
||||||
|
auto status = app.MonitorExecutionStatus(1);
|
||||||
|
assert(status == fzkj::ExecutionStatus::kInProgress);
|
||||||
|
std::cout << " ✓ 执行单元状态为执行中\n";
|
||||||
|
|
||||||
|
// 触发异常
|
||||||
|
ok = app.TriggerAlertOnFailure(1);
|
||||||
|
assert(ok);
|
||||||
|
status = app.MonitorExecutionStatus(1);
|
||||||
|
assert(status == fzkj::ExecutionStatus::kFailed);
|
||||||
|
std::cout << " ✓ 异常告警触发成功,状态变更为失败\n";
|
||||||
|
|
||||||
|
// 不存在的方案
|
||||||
|
ok = app.DispatchPlan(999);
|
||||||
|
assert(!ok);
|
||||||
|
std::cout << " ✓ 不存在的方案分发返回 false\n";
|
||||||
|
|
||||||
|
std::cout << " ✓ 方案分发与监控测试通过\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 测试用例:SRS-FZKJ_F-004 地图与量算
|
||||||
|
// ============================================================
|
||||||
|
static void TestMapAndMeasure() {
|
||||||
|
std::cout << "[Test] SRS-FZKJ_F-004 共用态势与地图...\n";
|
||||||
|
|
||||||
|
fzkj::App app;
|
||||||
|
|
||||||
|
// 加载地图
|
||||||
|
bool ok = app.LoadGisMap("test_map.tif");
|
||||||
|
assert(ok);
|
||||||
|
std::cout << " ✓ GIS 地图加载成功\n";
|
||||||
|
|
||||||
|
// 叠加图层
|
||||||
|
fzkj::SituationLayer layer{"雷达图层", true};
|
||||||
|
ok = app.OverlaySituationLayer(layer);
|
||||||
|
assert(ok);
|
||||||
|
std::cout << " ✓ 态势图层叠加成功\n";
|
||||||
|
|
||||||
|
// 量算距离(北京→上海约 1068 km)
|
||||||
|
fzkj::GeoPoint beijing{39.9042, 116.4074, 0.0};
|
||||||
|
fzkj::GeoPoint shanghai{31.2304, 121.4737, 0.0};
|
||||||
|
auto measure = app.MeasureDistance(beijing, shanghai);
|
||||||
|
// 预期在 1000~1200 km 之间
|
||||||
|
assert(measure.distance_m > 900000.0);
|
||||||
|
assert(measure.distance_m < 1300000.0);
|
||||||
|
std::cout << " ✓ 北京→上海距离量算: "
|
||||||
|
<< (measure.distance_m / 1000.0) << " km (预期约 1068 km)\n";
|
||||||
|
|
||||||
|
// 切换网格
|
||||||
|
app.ToggleGridDisplay();
|
||||||
|
std::cout << " ✓ 网格显示切换成功\n";
|
||||||
|
|
||||||
|
std::cout << " ✓ 地图与态势测试通过\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 测试用例:SRS-FZKJ_F-005 数据中转与存储
|
||||||
|
// ============================================================
|
||||||
|
static void TestDataTransfer() {
|
||||||
|
std::cout << "[Test] SRS-FZKJ_F-005 数据中转与存储...\n";
|
||||||
|
|
||||||
|
fzkj::App app;
|
||||||
|
|
||||||
|
uint8_t data[] = {10, 20, 30, 40};
|
||||||
|
bool ok = app.ForwardDataToModule("测试模块", data, sizeof(data));
|
||||||
|
assert(ok);
|
||||||
|
std::cout << " ✓ 数据转发成功\n";
|
||||||
|
|
||||||
|
ok = app.PersistCacheToDb();
|
||||||
|
assert(ok);
|
||||||
|
std::cout << " ✓ 缓存持久化成功\n";
|
||||||
|
|
||||||
|
ok = app.ClearScenarioCache();
|
||||||
|
assert(ok);
|
||||||
|
std::cout << " ✓ 想定缓存清空成功\n";
|
||||||
|
|
||||||
|
// 空数据应返回 false
|
||||||
|
ok = app.ForwardDataToModule("测试模块", nullptr, 10);
|
||||||
|
assert(!ok);
|
||||||
|
std::cout << " ✓ 空数据转发返回 false\n";
|
||||||
|
|
||||||
|
std::cout << " ✓ 数据中转测试通过\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 测试用例:SRS-FZKJ_F-006 系统设置与模式切换
|
||||||
|
// ============================================================
|
||||||
|
static void TestSystemConfig() {
|
||||||
|
std::cout << "[Test] SRS-FZKJ_F-006 系统设置与模式切换...\n";
|
||||||
|
|
||||||
|
fzkj::App app;
|
||||||
|
|
||||||
|
// 初始为正常模式
|
||||||
|
assert(app.GetCurrentMode() == fzkj::WorkMode::kNormal);
|
||||||
|
std::cout << " ✓ 初始模式为正常模式\n";
|
||||||
|
|
||||||
|
// 切换到降级模式
|
||||||
|
bool ok = app.SwitchExecutionMode(fzkj::WorkMode::kDegraded);
|
||||||
|
assert(ok);
|
||||||
|
assert(app.GetCurrentMode() == fzkj::WorkMode::kDegraded);
|
||||||
|
std::cout << " ✓ 切换到降级模式成功\n";
|
||||||
|
|
||||||
|
// 降级模式不能直接进入配置维护
|
||||||
|
ok = app.SwitchExecutionMode(fzkj::WorkMode::kConfigMaintain);
|
||||||
|
assert(!ok);
|
||||||
|
std::cout << " ✓ 降级→维护 转换被拒绝(符合状态图)\n";
|
||||||
|
|
||||||
|
// 降级→正常
|
||||||
|
ok = app.SwitchExecutionMode(fzkj::WorkMode::kNormal);
|
||||||
|
assert(ok);
|
||||||
|
std::cout << " ✓ 降级→正常 切换成功\n";
|
||||||
|
|
||||||
|
// 正常→配置维护
|
||||||
|
ok = app.SwitchExecutionMode(fzkj::WorkMode::kConfigMaintain);
|
||||||
|
assert(ok);
|
||||||
|
std::cout << " ✓ 正常→配置维护 切换成功\n";
|
||||||
|
|
||||||
|
// 配置维护只能回正常
|
||||||
|
ok = app.SwitchExecutionMode(fzkj::WorkMode::kDegraded);
|
||||||
|
assert(!ok);
|
||||||
|
std::cout << " ✓ 维护→降级 被拒绝\n";
|
||||||
|
|
||||||
|
ok = app.SwitchExecutionMode(fzkj::WorkMode::kNormal);
|
||||||
|
assert(ok);
|
||||||
|
std::cout << " ✓ 维护→正常 切换成功\n";
|
||||||
|
|
||||||
|
// 更新算法配置
|
||||||
|
app.SetAlgorithmConfig("强化学习算法", 0.8);
|
||||||
|
auto& cfg = app.GetConfig();
|
||||||
|
assert(cfg.algorithm_name == "强化学习算法");
|
||||||
|
assert(cfg.algorithm_param == 0.8);
|
||||||
|
std::cout << " ✓ 算法配置更新成功\n";
|
||||||
|
|
||||||
|
// 加载想定
|
||||||
|
ok = app.LoadScenarioParams("红蓝对抗想定-2025");
|
||||||
|
assert(ok);
|
||||||
|
assert(cfg.scenario_name == "红蓝对抗想定-2025");
|
||||||
|
std::cout << " ✓ 想定加载成功\n";
|
||||||
|
|
||||||
|
// 网络配置
|
||||||
|
ok = app.ApplyNetworkConfiguration("10.0.0.1", 8888);
|
||||||
|
assert(ok);
|
||||||
|
assert(cfg.ip_address == "10.0.0.1");
|
||||||
|
assert(cfg.port == 8888);
|
||||||
|
std::cout << " ✓ 网络配置更新成功\n";
|
||||||
|
|
||||||
|
std::cout << " ✓ 系统配置测试通过\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 测试用例:系统自检
|
||||||
|
// ============================================================
|
||||||
|
static void TestSelfCheck() {
|
||||||
|
std::cout << "[Test] 系统自检...\n";
|
||||||
|
fzkj::App app;
|
||||||
|
assert(app.SelfTest());
|
||||||
|
std::cout << " ✓ 系统自检通过\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 主测试入口
|
||||||
|
// ============================================================
|
||||||
|
int main() {
|
||||||
|
std::cout << "\n╔══════════════════════════════════════════╗\n";
|
||||||
|
std::cout << "║ FZKJ 核心软件 - 基础单元测试套件 ║\n";
|
||||||
|
std::cout << "║ 版本 1.6.0 标准库 assert ║\n";
|
||||||
|
std::cout << "╚══════════════════════════════════════════╝\n\n";
|
||||||
|
|
||||||
|
TestDataStructures();
|
||||||
|
TestEventProcessing();
|
||||||
|
TestSolutionManagement();
|
||||||
|
TestPlanDispatch();
|
||||||
|
TestMapAndMeasure();
|
||||||
|
TestDataTransfer();
|
||||||
|
TestSystemConfig();
|
||||||
|
TestSelfCheck();
|
||||||
|
|
||||||
|
std::cout << "╔══════════════════════════════════════════╗\n";
|
||||||
|
std::cout << "║ 全部测试通过! ✓ ║\n";
|
||||||
|
std::cout << "╚══════════════════════════════════════════╝\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue