综合平台编程器项目的远程存储
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

176 line
4.5 KiB

  1. #include "project_model.h"
  2. #include <algorithm>
  3. namespace {
  4. void setError(std::string *error, const std::string &message)
  5. {
  6. if (error != nullptr)
  7. {
  8. *error = message;
  9. }
  10. }
  11. // 通过相邻区间查找避免为不同领域对象重复实现标识唯一性校验
  12. template <typename TItem>
  13. bool containsDuplicateId(const std::vector<TItem> &items)
  14. {
  15. for (auto current = items.cbegin(); current != items.cend(); ++current)
  16. {
  17. const auto duplicate = std::find_if(
  18. current + 1,
  19. items.cend(),
  20. [&current](const TItem &item)
  21. {
  22. return item.id == current->id;
  23. });
  24. if (duplicate != items.cend())
  25. {
  26. return true;
  27. }
  28. }
  29. return false;
  30. }
  31. template <typename TItem>
  32. bool containsDuplicateName(const std::vector<TItem> &items)
  33. {
  34. for (auto current = items.cbegin(); current != items.cend(); ++current)
  35. {
  36. const auto duplicate = std::find_if(
  37. current + 1,
  38. items.cend(),
  39. [&current](const TItem &item)
  40. {
  41. return item.name == current->name;
  42. });
  43. if (duplicate != items.cend())
  44. {
  45. return true;
  46. }
  47. }
  48. return false;
  49. }
  50. } // namespace
  51. bool Project::validate(std::string *error) const
  52. {
  53. if (metadata.id.empty() || metadata.name.empty() || metadata.formatVersion.empty())
  54. {
  55. setError(error, "工程 ID、名称和格式版本不能为空");
  56. return false;
  57. }
  58. if (containsDuplicateId(hmiPages))
  59. {
  60. setError(error, "工程内的 HMI 页面 ID 必须唯一");
  61. return false;
  62. }
  63. if (containsDuplicateName(hmiPages))
  64. {
  65. setError(error, "工程内的 HMI 页面名称必须唯一");
  66. return false;
  67. }
  68. if (hmiPages.empty())
  69. {
  70. if (!initialHmiPageId.empty())
  71. {
  72. setError(error, "空工程不能设置初始 HMI 页面");
  73. return false;
  74. }
  75. }
  76. else
  77. {
  78. const auto initial_page = std::find_if(
  79. hmiPages.cbegin(), hmiPages.cend(),
  80. [this](const HmiPage &page) { return page.id == initialHmiPageId; });
  81. if (initial_page == hmiPages.cend())
  82. {
  83. setError(error, "工程初始 HMI 页面不存在");
  84. return false;
  85. }
  86. }
  87. if (containsDuplicateId(controlLogics))
  88. {
  89. setError(error, "工程内的控制逻辑 ID 必须唯一");
  90. return false;
  91. }
  92. if (containsDuplicateName(controlLogics))
  93. {
  94. setError(error, "工程内的控制逻辑名称必须唯一");
  95. return false;
  96. }
  97. if (containsDuplicateId(alarmDefinitions))
  98. {
  99. setError(error, "工程内的报警定义 ID 必须唯一");
  100. return false;
  101. }
  102. for (const AlarmDefinition &definition : alarmDefinitions)
  103. {
  104. if (!definition.validate(error))
  105. {
  106. return false;
  107. }
  108. }
  109. for (const HmiPage &page : hmiPages)
  110. {
  111. // 工程聚合校验会向下委托页面和控件的完整规则
  112. if (!page.validate(error))
  113. {
  114. return false;
  115. }
  116. for (const HmiControl &control : page.controls)
  117. {
  118. if (control.type != HmiControlType::PageJump
  119. || !control.pageJump.has_value()
  120. || control.pageJump->targetPageId.empty())
  121. {
  122. continue;
  123. }
  124. const auto target = std::find_if(
  125. hmiPages.cbegin(), hmiPages.cend(),
  126. [&control](const HmiPage &candidate)
  127. {
  128. return candidate.id == control.pageJump->targetPageId;
  129. });
  130. if (target == hmiPages.cend())
  131. {
  132. setError(error, "页面跳转控件 " + control.id + " 的目标页面不存在");
  133. return false;
  134. }
  135. }
  136. }
  137. for (const ControlLogic &logic : controlLogics)
  138. {
  139. if (!logic.validate(error))
  140. {
  141. return false;
  142. }
  143. }
  144. return true;
  145. }
  146. bool Project::validateForRunning(std::string *error) const
  147. {
  148. if (!validate(error))
  149. {
  150. return false;
  151. }
  152. for (const HmiPage &page : hmiPages)
  153. {
  154. if (!page.validateForRunning(error))
  155. {
  156. return false;
  157. }
  158. }
  159. for (const ControlLogic &logic : controlLogics)
  160. {
  161. if (logic.enabled && !logic.validateForRunning(error))
  162. {
  163. return false;
  164. }
  165. }
  166. return true;
  167. }