|
- #include "project_model.h"
-
- #include <algorithm>
-
- namespace {
-
- void setError(std::string *error, const std::string &message)
- {
- if (error != nullptr)
- {
- *error = message;
- }
- }
-
- // 通过相邻区间查找避免为不同领域对象重复实现标识唯一性校验
- template <typename TItem>
- bool containsDuplicateId(const std::vector<TItem> &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 <typename TItem>
- bool containsDuplicateName(const std::vector<TItem> &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;
- }
|