#include "project_model.h" #include namespace { void setError(std::string *error, const std::string &message) { if (error != nullptr) { *error = message; } } // 通过相邻区间查找避免为不同领域对象重复实现标识唯一性校验 template bool containsDuplicateId(const std::vector &items) { for (auto current = items.cbegin(); current != items.cend(); ++current) { const auto duplicate = std::find_if( current + 1, items.cend(), [¤t](const TItem &item) { return item.id == current->id; }); if (duplicate != items.cend()) { return true; } } return false; } template bool containsDuplicateName(const std::vector &items) { for (auto current = items.cbegin(); current != items.cend(); ++current) { const auto duplicate = std::find_if( current + 1, items.cend(), [¤t](const TItem &item) { return item.name == current->name; }); if (duplicate != items.cend()) { return true; } } return false; } } // namespace bool Project::validate(std::string *error) const { if (metadata.id.empty() || metadata.name.empty() || metadata.formatVersion.empty()) { setError(error, "工程 ID、名称和格式版本不能为空"); return false; } if (containsDuplicateId(hmiPages)) { setError(error, "工程内的 HMI 页面 ID 必须唯一"); return false; } if (containsDuplicateName(hmiPages)) { setError(error, "工程内的 HMI 页面名称必须唯一"); return false; } if (hmiPages.empty()) { if (!initialHmiPageId.empty()) { setError(error, "空工程不能设置初始 HMI 页面"); return false; } } else { const auto initial_page = std::find_if( hmiPages.cbegin(), hmiPages.cend(), [this](const HmiPage &page) { return page.id == initialHmiPageId; }); if (initial_page == hmiPages.cend()) { setError(error, "工程初始 HMI 页面不存在"); return false; } } if (containsDuplicateId(controlLogics)) { setError(error, "工程内的控制逻辑 ID 必须唯一"); return false; } if (containsDuplicateName(controlLogics)) { setError(error, "工程内的控制逻辑名称必须唯一"); return false; } if (containsDuplicateId(alarmDefinitions)) { setError(error, "工程内的报警定义 ID 必须唯一"); return false; } for (const AlarmDefinition &definition : alarmDefinitions) { if (!definition.validate(error)) { return false; } } for (const HmiPage &page : hmiPages) { // 工程聚合校验会向下委托页面和控件的完整规则 if (!page.validate(error)) { return false; } for (const HmiControl &control : page.controls) { if (control.type != HmiControlType::PageJump || !control.pageJump.has_value() || control.pageJump->targetPageId.empty()) { continue; } const auto target = std::find_if( hmiPages.cbegin(), hmiPages.cend(), [&control](const HmiPage &candidate) { return candidate.id == control.pageJump->targetPageId; }); if (target == hmiPages.cend()) { setError(error, "页面跳转控件 " + control.id + " 的目标页面不存在"); return false; } } } for (const ControlLogic &logic : controlLogics) { if (!logic.validate(error)) { return false; } } return true; } bool Project::validateForRunning(std::string *error) const { if (!validate(error)) { return false; } for (const HmiPage &page : hmiPages) { if (!page.validateForRunning(error)) { return false; } } for (const ControlLogic &logic : controlLogics) { if (logic.enabled && !logic.validateForRunning(error)) { return false; } } return true; }