Explorar el Código

refactor: 统一业务错误中文提示

main
suyu hace 1 mes
padre
commit
1ea027975c
Se han modificado 10 ficheros con 114 adiciones y 114 borrados
  1. +22
    -22
      app/src/domain/control_logic_model.cpp
  2. +11
    -11
      app/src/domain/hmi_model.cpp
  3. +3
    -3
      app/src/domain/project_model.cpp
  4. +26
    -26
      app/src/infrastructure/json_project_storage.cpp
  5. +15
    -15
      app/src/services/hmi_editor_service.cpp
  6. +20
    -20
      app/src/services/logic_editor_service.cpp
  7. +1
    -1
      app/src/services/offline_simulation_service.cpp
  8. +5
    -5
      app/src/services/project_service.cpp
  9. +1
    -1
      app/src/services/runtime_mode_service.cpp
  10. +10
    -10
      app/src/services/software_logic_executor.cpp

+ 22
- 22
app/src/domain/control_logic_model.cpp Ver fichero

@@ -17,13 +17,13 @@ bool validateConfig(const ContactNodeConfig &config, std::string *error)
{
if (!config.address.isValid() || config.address.area() != RegisterArea::M)
{
setError(error, "contact node requires a valid M address");
setError(error, "触点节点必须使用有效的 M 区地址");
return false;
}
if (config.mode != ContactMode::NormallyOpen
&& config.mode != ContactMode::NormallyClosed)
{
setError(error, "contact node has an unsupported mode");
setError(error, "触点节点使用了不支持的模式");
return false;
}
return true;
@@ -33,14 +33,14 @@ bool validateConfig(const CoilNodeConfig &config, std::string *error)
{
if (!config.address.isValid() || config.address.area() != RegisterArea::M)
{
setError(error, "coil node requires a valid M address");
setError(error, "线圈节点必须使用有效的 M 区地址");
return false;
}
if (config.mode != CoilMode::Normal
&& config.mode != CoilMode::Set
&& config.mode != CoilMode::Reset)
{
setError(error, "coil node has an unsupported mode");
setError(error, "线圈节点使用了不支持的模式");
return false;
}
return true;
@@ -50,7 +50,7 @@ bool validateConfig(const CompareNodeConfig &config, std::string *error)
{
if (!config.address.isValid() || config.address.area() != RegisterArea::D)
{
setError(error, "comparison node requires a valid D address");
setError(error, "比较节点必须使用有效的 D 区地址");
return false;
}
if (config.comparison != ComparisonOperator::Equal
@@ -60,7 +60,7 @@ bool validateConfig(const CompareNodeConfig &config, std::string *error)
&& config.comparison != ComparisonOperator::GreaterThan
&& config.comparison != ComparisonOperator::GreaterThanOrEqual)
{
setError(error, "comparison node has an unsupported operator");
setError(error, "比较节点使用了不支持的运算符");
return false;
}
return true;
@@ -93,7 +93,7 @@ bool validateUniqueExpressionIds(
std::sort(ids.begin(), ids.end());
if (std::adjacent_find(ids.cbegin(), ids.cend()) != ids.cend())
{
setError(error, "condition expression ids must be unique within a rung");
setError(error, "同一网络内的条件表达式 ID 必须唯一");
return false;
}
return true;
@@ -138,7 +138,7 @@ bool LogicNode::validate(std::string *error) const
{
if (id.empty())
{
setError(error, "logic node id must not be empty");
setError(error, "逻辑节点 ID 不能为空");
return false;
}
return std::visit(
@@ -174,28 +174,28 @@ bool ConditionExpression::validate(std::string *error) const
{
if (id.empty())
{
setError(error, "condition expression id must not be empty");
setError(error, "条件表达式 ID 不能为空");
return false;
}
if (kind == ConditionExpressionKind::Node)
{
if (!node.has_value() || !children.empty() || !node->isCondition())
{
setError(error, "condition leaf requires one condition node and no children");
setError(error, "条件叶节点必须包含一个条件节点且不能包含子表达式");
return false;
}
return node->validate(error);
}
if (node.has_value() || children.size() < 2U)
{
setError(error, "series and parallel expressions require at least two children");
setError(error, "串联和并联表达式至少需要两个子表达式");
return false;
}
for (const ConditionExpression &child : children)
{
if (child.kind == kind)
{
setError(error, "nested expressions of the same kind must be normalized");
setError(error, "同类型嵌套表达式必须先完成归一化");
return false;
}
if (!child.validate(error))
@@ -216,7 +216,7 @@ bool ConditionExpression::validateForRunning(std::string *error) const
{
if (!node->isConfigured())
{
setError(error, "ladder condition " + node->id + " is not configured");
setError(error, "梯形图条件节点 " + node->id + " 尚未配置");
return false;
}
return true;
@@ -343,7 +343,7 @@ bool LadderRung::validateForRunning(std::string *error) const
}
if (!condition.has_value() || !output.has_value())
{
setError(error, "incomplete ladder network requires conditions and an output coil");
setError(error, "未完成的梯形图网络必须同时包含条件和输出线圈");
return false;
}
if (!condition->validateForRunning(error))
@@ -352,7 +352,7 @@ bool LadderRung::validateForRunning(std::string *error) const
}
if (!output->isConfigured())
{
setError(error, "output coil " + output->id + " is not configured");
setError(error, "输出线圈 " + output->id + " 尚未配置");
return false;
}
return true;
@@ -362,7 +362,7 @@ bool LadderRung::validateStructure(std::string *error) const
{
if (id.empty() || name.empty())
{
setError(error, "ladder rung id and name must not be empty");
setError(error, "梯形图网络 ID 和名称不能为空");
return false;
}
std::vector<std::string> node_ids;
@@ -383,7 +383,7 @@ bool LadderRung::validateStructure(std::string *error) const
{
if (!output->validate(error) || !output->isOutput())
{
setError(error, "ladder rung output must be a coil node");
setError(error, "梯形图网络输出必须是线圈节点");
return false;
}
node_ids.push_back(output->id);
@@ -391,7 +391,7 @@ bool LadderRung::validateStructure(std::string *error) const
std::sort(node_ids.begin(), node_ids.end());
if (std::adjacent_find(node_ids.cbegin(), node_ids.cend()) != node_ids.cend())
{
setError(error, "logic node ids must be unique within a rung");
setError(error, "同一网络内的逻辑节点 ID 必须唯一");
return false;
}
return true;
@@ -417,12 +417,12 @@ bool ControlLogic::validateStructure(std::string *error) const
{
if (id.empty() || name.empty())
{
setError(error, "control logic id and name must not be empty");
setError(error, "控制逻辑 ID 和名称不能为空");
return false;
}
if (hasDuplicateId(rungs))
{
setError(error, "ladder rung ids must be unique within a logic");
setError(error, "同一控制逻辑内的网络 ID 必须唯一");
return false;
}
std::vector<std::string> node_ids;
@@ -452,13 +452,13 @@ bool ControlLogic::validateStructure(std::string *error) const
std::sort(expression_ids.begin(), expression_ids.end());
if (std::adjacent_find(node_ids.cbegin(), node_ids.cend()) != node_ids.cend())
{
setError(error, "logic node ids must be unique within a logic");
setError(error, "同一控制逻辑内的逻辑节点 ID 必须唯一");
return false;
}
if (std::adjacent_find(expression_ids.cbegin(), expression_ids.cend())
!= expression_ids.cend())
{
setError(error, "condition expression ids must be unique within a logic");
setError(error, "同一控制逻辑内的条件表达式 ID 必须唯一");
return false;
}
return true;


+ 11
- 11
app/src/domain/hmi_model.cpp Ver fichero

@@ -31,19 +31,19 @@ bool HmiControl::validate(std::string *error) const
{
if (id.empty())
{
setError(error, "HMI control id must not be empty");
setError(error, "HMI 控件 ID 不能为空");
return false;
}
if (bounds.width <= 0 || bounds.height <= 0)
{
setError(error, "HMI control bounds must have positive size");
setError(error, "HMI 控件的宽度和高度必须大于 0");
return false;
}
for (const auto &property : properties)
{
if (property.first.empty())
{
setError(error, "HMI control property names must not be empty");
setError(error, "HMI 控件属性名称不能为空");
return false;
}
}
@@ -51,7 +51,7 @@ bool HmiControl::validate(std::string *error) const
{
if (binding.has_value() && binding->area() != RegisterArea::M)
{
setError(error, "button and indicator controls require an M address");
setError(error, "按钮和指示灯必须绑定 M 区地址");
return false;
}
}
@@ -59,13 +59,13 @@ bool HmiControl::validate(std::string *error) const
{
if (binding.has_value() && binding->area() != RegisterArea::D)
{
setError(error, "numeric controls require a D address");
setError(error, "数值控件必须绑定 D 区地址");
return false;
}
}
if (binding.has_value() && !binding->isValid())
{
setError(error, "HMI control binding has an invalid address");
setError(error, "HMI 控件绑定了无效地址");
return false;
}
return true;
@@ -92,12 +92,12 @@ bool HmiPage::validate(std::string *error) const
{
if (id.empty() || name.empty())
{
setError(error, "HMI page id and name must not be empty");
setError(error, "HMI 页面 ID 和名称不能为空");
return false;
}
if (width <= 0 || height <= 0)
{
setError(error, "HMI page size must be positive");
setError(error, "HMI 页面尺寸必须大于 0");
return false;
}

@@ -113,13 +113,13 @@ bool HmiPage::validate(std::string *error) const
|| control.bounds.x > width - control.bounds.width
|| control.bounds.y > height - control.bounds.height)
{
setError(error, "HMI control bounds must stay within the page");
setError(error, "HMI 控件不能超出页面范围");
return false;
}
// 检查控件 id 是否唯一
if (std::find(ids.cbegin(), ids.cend(), control.id) != ids.cend())
{
setError(error, "HMI control ids must be unique within a page");
setError(error, "同一 HMI 页面内的控件 ID 必须唯一");
return false;
}
ids.push_back(control.id);
@@ -137,7 +137,7 @@ bool HmiPage::validateForRunning(std::string *error) const
{
if (!control.isConfigured())
{
setError(error, "HMI control " + control.id + " is not bound to a register");
setError(error, "HMI 控件 " + control.id + " 尚未绑定寄存器");
return false;
}
}


+ 3
- 3
app/src/domain/project_model.cpp Ver fichero

@@ -39,17 +39,17 @@ bool Project::validate(std::string *error) const
{
if (metadata.id.empty() || metadata.name.empty() || metadata.formatVersion.empty())
{
setError(error, "project id, name and format version must not be empty");
setError(error, "工程 ID、名称和格式版本不能为空");
return false;
}
if (containsDuplicateId(hmiPages))
{
setError(error, "HMI page ids must be unique within a project");
setError(error, "工程内的 HMI 页面 ID 必须唯一");
return false;
}
if (containsDuplicateId(controlLogics))
{
setError(error, "control logic ids must be unique within a project");
setError(error, "工程内的控制逻辑 ID 必须唯一");
return false;
}
for (const HmiPage &page : hmiPages)


+ 26
- 26
app/src/infrastructure/json_project_storage.cpp Ver fichero

@@ -67,7 +67,7 @@ bool readValue(
{
return state->fail(
ProjectStorageError::MissingField,
"missing required field " + fieldPath(context, field));
"缺少必填字段:" + fieldPath(context, field));
}
*value = object.value(key);
return true;
@@ -90,7 +90,7 @@ bool readString(
{
return state->fail(
ProjectStorageError::InvalidField,
fieldPath(context, field) + " must be a string");
fieldPath(context, field) + " 必须是字符串");
}
*value = toUtf8(json_value.toString());
return true;
@@ -113,7 +113,7 @@ bool readBool(
{
return state->fail(
ProjectStorageError::InvalidField,
fieldPath(context, field) + " must be a boolean");
fieldPath(context, field) + " 必须是布尔值");
}
*value = json_value.toBool();
return true;
@@ -138,7 +138,7 @@ bool readInt(
{
return state->fail(
ProjectStorageError::InvalidField,
fieldPath(context, field) + " must be an integer");
fieldPath(context, field) + " 必须是整数");
}

// Qt JSON 统一用 double 表示数值,需要额外确认它能无损转换为 int
@@ -148,7 +148,7 @@ bool readInt(
{
return state->fail(
ProjectStorageError::InvalidField,
fieldPath(context, field) + " is outside the supported integer range");
fieldPath(context, field) + " 超出支持的整数范围");
}
*value = static_cast<int>(number);
return true;
@@ -171,7 +171,7 @@ bool readObject(
{
return state->fail(
ProjectStorageError::InvalidField,
fieldPath(context, field) + " must be an object");
fieldPath(context, field) + " 必须是对象");
}
*value = json_value.toObject();
return true;
@@ -194,7 +194,7 @@ bool readArray(
{
return state->fail(
ProjectStorageError::InvalidField,
fieldPath(context, field) + " must be an array");
fieldPath(context, field) + " 必须是数组");
}
*value = json_value.toArray();
return true;
@@ -246,7 +246,7 @@ bool parseAddress(
{
return state->fail(
ProjectStorageError::InvalidField,
context + ".area must be M or D");
context + ".area 必须是 M 或 D");
}

*address = RegisterAddress{area, index};
@@ -313,7 +313,7 @@ bool parseHmiControlType(
{
return state->fail(
ProjectStorageError::InvalidField,
"unsupported HMI control type " + value);
"不支持的 HMI 控件类型:" + value);
}
return true;
}
@@ -393,7 +393,7 @@ bool parseProperties(
{
return state->fail(
ProjectStorageError::InvalidField,
"HMI control property values must be strings");
"HMI 控件属性值必须是字符串");
}
properties->emplace(toUtf8(current.key()), toUtf8(current.value().toString()));
}
@@ -458,7 +458,7 @@ bool parseHmiControl(
{
return state->fail(
ProjectStorageError::InvalidField,
context + ".binding must be an object or null");
context + ".binding 必须是对象或 null");
}

RegisterAddress address{RegisterArea::M, 0};
@@ -515,7 +515,7 @@ bool parseHmiPage(
{
return state->fail(
ProjectStorageError::InvalidField,
context + ".controls items must be objects");
context + ".controls 的元素必须是对象");
}
HmiControl control;
if (!parseHmiControl(
@@ -555,7 +555,7 @@ bool parseContactMode(
{
return state->fail(
ProjectStorageError::InvalidField,
"unsupported contact mode " + value);
"不支持的触点模式:" + value);
}
return true;
}
@@ -603,7 +603,7 @@ bool parseCoilMode(const std::string &value, CoilMode *mode, ParseState *state)
{
return state->fail(
ProjectStorageError::InvalidField,
"unsupported coil mode " + value);
"不支持的线圈模式:" + value);
}
return true;
}
@@ -678,7 +678,7 @@ bool parseComparison(
{
return state->fail(
ProjectStorageError::InvalidField,
"unsupported comparison operator " + value);
"不支持的比较运算符:" + value);
}
return true;
}
@@ -804,7 +804,7 @@ bool parseNodeConfig(

return state->fail(
ProjectStorageError::InvalidField,
"unsupported logic node type " + type);
"不支持的逻辑节点类型:" + type);
}

// 解析逻辑节点标识及其多态配置
@@ -892,7 +892,7 @@ bool parseConditionExpression(
{
return state->fail(
ProjectStorageError::InvalidField,
context + ".kind must be node, series or parallel");
context + ".kind 必须是 node、series 或 parallel");
}
QJsonArray children;
if (!readArray(object, "children", context, &children, state))
@@ -908,7 +908,7 @@ bool parseConditionExpression(
{
return state->fail(
ProjectStorageError::InvalidField,
context + ".children items must be objects");
context + ".children 的元素必须是对象");
}
ConditionExpression child;
if (!parseConditionExpression(
@@ -967,7 +967,7 @@ bool parseLadderRung(
{
return state->fail(
ProjectStorageError::InvalidField,
context + ".condition must be an object or null");
context + ".condition 必须是对象或 null");
}
else
{
@@ -988,7 +988,7 @@ bool parseLadderRung(
{
return state->fail(
ProjectStorageError::InvalidField,
context + ".output must be an object or null");
context + ".output 必须是对象或 null");
}
LogicNode node;
if (!parseLogicNode(output.toObject(), context + ".output", &node, state))
@@ -1035,7 +1035,7 @@ bool parseControlLogic(
{
return state->fail(
ProjectStorageError::InvalidField,
context + ".rungs items must be objects");
context + ".rungs 的元素必须是对象");
}
LadderRung rung;
if (!parseLadderRung(
@@ -1095,7 +1095,7 @@ bool parseProject(
{
return state->fail(
ProjectStorageError::UnsupportedVersion,
"unsupported project format version " + project->metadata.formatVersion);
"不支持的工程格式版本:" + project->metadata.formatVersion);
}

if (!readString(object, "id", "project", &project->metadata.id, state)
@@ -1114,7 +1114,7 @@ bool parseProject(
{
return state->fail(
ProjectStorageError::InvalidField,
"project.hmiPages items must be objects");
"project.hmiPages 的元素必须是对象");
}
HmiPage page;
if (!parseHmiPage(
@@ -1135,7 +1135,7 @@ bool parseProject(
{
return state->fail(
ProjectStorageError::InvalidField,
"project.controlLogics items must be objects");
"project.controlLogics 的元素必须是对象");
}
ControlLogic logic;
if (!parseControlLogic(
@@ -1174,7 +1174,7 @@ ProjectSaveResult JsonProjectStorage::save(
{
return {false,
ProjectStorageError::UnsupportedVersion,
"unsupported project format version " + project.metadata.formatVersion};
"不支持的工程格式版本:" + project.metadata.formatVersion};
}

// QSaveFile 先写临时文件,仅在 commit 成功后替换目标文件
@@ -1226,7 +1226,7 @@ ProjectLoadResult JsonProjectStorage::load(const std::string &file_path)
if (parse_error.error != QJsonParseError::NoError || !document.isObject())
{
const QString message = parse_error.error == QJsonParseError::NoError
? QStringLiteral("project JSON root must be an object")
? QStringLiteral("工程 JSON 根节点必须是对象")
: parse_error.errorString();
return {false,
{},


+ 15
- 15
app/src/services/hmi_editor_service.cpp Ver fichero

@@ -147,7 +147,7 @@ HmiEditorResult HmiEditorService::addControl(
const HmiPage *page = findPage(page_id);
if (page == nullptr)
{
return failure(HmiEditorError::PageNotFound, "HMI page was not found");
return failure(HmiEditorError::PageNotFound, "未找到 HMI 页面");
}

// 新控件初始不绑定寄存器,避免自动分配地址造成误写风险
@@ -172,11 +172,11 @@ HmiEditorResult HmiEditorService::removeControl(
{
if (findPage(page_id) == nullptr)
{
return failure(HmiEditorError::PageNotFound, "HMI page was not found");
return failure(HmiEditorError::PageNotFound, "未找到 HMI 页面");
}
if (findControl(page_id, control_id) == nullptr)
{
return failure(HmiEditorError::ControlNotFound, "HMI control was not found");
return failure(HmiEditorError::ControlNotFound, "未找到 HMI 控件");
}

Project &project = project_service_.editProject();
@@ -209,11 +209,11 @@ HmiEditorResult HmiEditorService::moveControl(
const HmiControl *control = findControl(page_id, control_id);
if (page == nullptr)
{
return failure(HmiEditorError::PageNotFound, "HMI page was not found");
return failure(HmiEditorError::PageNotFound, "未找到 HMI 页面");
}
if (control == nullptr)
{
return failure(HmiEditorError::ControlNotFound, "HMI control was not found");
return failure(HmiEditorError::ControlNotFound, "未找到 HMI 控件");
}

// 先校验候选位置,失败时不修改工程模型
@@ -247,15 +247,15 @@ HmiEditorResult HmiEditorService::updateControl(
const HmiControl *existing = findControl(page_id, control_id);
if (page == nullptr)
{
return failure(HmiEditorError::PageNotFound, "HMI page was not found");
return failure(HmiEditorError::PageNotFound, "未找到 HMI 页面");
}
if (existing == nullptr)
{
return failure(HmiEditorError::ControlNotFound, "HMI control was not found");
return failure(HmiEditorError::ControlNotFound, "未找到 HMI 控件");
}
if (control.type != existing->type)
{
return failure(HmiEditorError::InvalidControl, "HMI control type cannot be changed");
return failure(HmiEditorError::InvalidControl, "不能修改已创建 HMI 控件的类型");
}

std::string error;
@@ -265,7 +265,7 @@ HmiEditorResult HmiEditorService::updateControl(
}
if (hasDuplicateControlId(*page, control_id, control.id))
{
return failure(HmiEditorError::DuplicateId, "HMI control id must be unique within a page");
return failure(HmiEditorError::DuplicateId, "同一 HMI 页面内的控件 ID 必须唯一");
}

Project &project = project_service_.editProject();
@@ -284,7 +284,7 @@ bool HmiEditorService::validateEditableControl(
{
if (control.id.empty())
{
setError(error, "HMI control id must not be empty");
setError(error, "HMI 控件 ID 不能为空");
return false;
}
if (control.bounds.width <= 0 || control.bounds.height <= 0
@@ -293,20 +293,20 @@ bool HmiEditorService::validateEditableControl(
|| control.bounds.x > page.width - control.bounds.width
|| control.bounds.y > page.height - control.bounds.height)
{
setError(error, "HMI control bounds must stay within the page");
setError(error, "HMI 控件不能超出页面范围");
return false;
}
for (const auto &property : control.properties)
{
if (property.first.empty())
{
setError(error, "HMI control property names must not be empty");
setError(error, "HMI 控件属性名称不能为空");
return false;
}
}
if (control.binding.has_value() && !control.binding->isValid())
{
setError(error, "HMI control binding has an invalid address");
setError(error, "HMI 控件绑定了无效地址");
return false;
}
if (control.binding.has_value()
@@ -314,7 +314,7 @@ bool HmiEditorService::validateEditableControl(
|| control.type == HmiControlType::Indicator)
&& control.binding->area() != RegisterArea::M)
{
setError(error, "button and indicator controls require an M address");
setError(error, "按钮和指示灯必须绑定 M 区地址");
return false;
}
if (control.binding.has_value()
@@ -322,7 +322,7 @@ bool HmiEditorService::validateEditableControl(
|| control.type == HmiControlType::NumericInput)
&& control.binding->area() != RegisterArea::D)
{
setError(error, "numeric controls require a D address");
setError(error, "数值控件必须绑定 D 区地址");
return false;
}
return true;


+ 20
- 20
app/src/services/logic_editor_service.cpp Ver fichero

@@ -346,7 +346,7 @@ LogicEditorResult LogicEditorService::addRung(const std::string &logic_id)
const ControlLogic *logic = findLogic(logic_id);
if (logic == nullptr)
{
return failure(LogicEditorError::LogicNotFound, "control logic was not found");
return failure(LogicEditorError::LogicNotFound, "未找到控制逻辑");
}
LadderRung rung;
rung.id = makeUniqueRungId(*logic);
@@ -365,15 +365,15 @@ LogicEditorResult LogicEditorService::removeRung(
const ControlLogic *logic = findLogic(logic_id);
if (logic == nullptr)
{
return failure(LogicEditorError::LogicNotFound, "control logic was not found");
return failure(LogicEditorError::LogicNotFound, "未找到控制逻辑");
}
if (findRung(logic_id, rung_id) == nullptr)
{
return failure(LogicEditorError::RungNotFound, "ladder rung was not found");
return failure(LogicEditorError::RungNotFound, "未找到梯形图网络");
}
if (logic->rungs.size() == 1U)
{
return failure(LogicEditorError::InvalidOperation, "control logic requires one rung");
return failure(LogicEditorError::InvalidOperation, "控制逻辑至少需要保留一个网络");
}
Project &project = project_service_.editProject();
auto target = std::find_if(
@@ -397,11 +397,11 @@ LogicEditorResult LogicEditorService::appendCondition(
{
return failure(
logic == nullptr ? LogicEditorError::LogicNotFound : LogicEditorError::RungNotFound,
logic == nullptr ? "control logic was not found" : "ladder rung was not found");
logic == nullptr ? "未找到控制逻辑" : "未找到梯形图网络");
}
if (!isConditionConfig(config))
{
return failure(LogicEditorError::InvalidNode, "ladder condition cannot be a coil");
return failure(LogicEditorError::InvalidNode, "梯形图条件不能使用线圈节点");
}
const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config));
ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config));
@@ -435,7 +435,7 @@ LogicEditorResult LogicEditorService::insertConditionAfter(
const ControlLogic *logic = findLogic(logic_id);
if (logic == nullptr || findRung(logic_id, rung_id) == nullptr)
{
return failure(LogicEditorError::RungNotFound, "ladder network was not found");
return failure(LogicEditorError::RungNotFound, "未找到梯形图网络");
}
const LadderRung *existing_rung = findRung(logic_id, rung_id);
if (!isConditionConfig(config)
@@ -443,7 +443,7 @@ LogicEditorResult LogicEditorService::insertConditionAfter(
|| !existing_rung->condition.has_value()
|| findConditionNode(*existing_rung->condition, target_node_id) == nullptr)
{
return failure(LogicEditorError::NodeNotFound, "series insertion target was not found");
return failure(LogicEditorError::NodeNotFound, "未找到串联插入目标");
}
const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config));
ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config));
@@ -482,30 +482,30 @@ LogicEditorResult LogicEditorService::addParallelBranch(
const ControlLogic *logic = findLogic(logic_id);
if (logic == nullptr || findRung(logic_id, rung_id) == nullptr)
{
return failure(LogicEditorError::RungNotFound, "ladder network was not found");
return failure(LogicEditorError::RungNotFound, "未找到梯形图网络");
}
if (!isConditionConfig(config) || selected_node_ids.empty())
{
return failure(LogicEditorError::InvalidOperation, "parallel branch requires a selection");
return failure(LogicEditorError::InvalidOperation, "建立并联支路前必须选择节点");
}
const LadderRung *existing_rung = findRung(logic_id, rung_id);
if (!existing_rung->condition.has_value())
{
return failure(LogicEditorError::InvalidOperation, "ladder network has no condition");
return failure(LogicEditorError::InvalidOperation, "梯形图网络尚无条件节点");
}
NodeIdSet selected_ids(selected_node_ids.cbegin(), selected_node_ids.cend());
if (selected_ids.size() != selected_node_ids.size())
{
return failure(
LogicEditorError::InvalidOperation,
"parallel selection contains duplicates");
"并联选择中存在重复节点");
}
const NodeIdSet available_ids = conditionNodeIds(*existing_rung->condition);
if (!isSubset(selected_ids, available_ids))
{
return failure(
LogicEditorError::NodeNotFound,
"parallel selection contains an unknown node");
"并联选择中包含未知节点");
}
const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config));
ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config));
@@ -526,7 +526,7 @@ LogicEditorResult LogicEditorService::addParallelBranch(
{
return failure(
LogicEditorError::InvalidOperation,
"parallel selection must be one continuous logic range");
"并联选择必须是一个连续的逻辑范围");
}
return {true, LogicEditorError::None, {}, node_id};
}
@@ -540,7 +540,7 @@ LogicEditorResult LogicEditorService::setOutput(
const LadderRung *existing_rung = findRung(logic_id, rung_id);
if (logic == nullptr || existing_rung == nullptr || !isOutputConfig(config))
{
return failure(LogicEditorError::InvalidNode, "ladder output requires a valid coil");
return failure(LogicEditorError::InvalidNode, "梯形图输出必须使用有效线圈");
}
const std::string node_id = existing_rung->output.has_value()
? existing_rung->output->id : makeUniqueNodeId(*logic, nodePrefix(config));
@@ -557,13 +557,13 @@ LogicEditorResult LogicEditorService::updateNodeConfig(
const LogicNode *node = findNode(logic_id, node_id);
if (node == nullptr)
{
return failure(LogicEditorError::NodeNotFound, "logic node was not found");
return failure(LogicEditorError::NodeNotFound, "未找到逻辑节点");
}
if (node->config.index() != config.index())
{
return failure(
LogicEditorError::UnsupportedNodeChange,
"node category cannot be changed after creation");
"节点创建后不能修改节点类别");
}
LogicNode candidate{node_id, config, true};
std::string error;
@@ -595,7 +595,7 @@ LogicEditorResult LogicEditorService::updateNodeConfig(
}
}
}
return failure(LogicEditorError::NodeNotFound, "logic node was not found");
return failure(LogicEditorError::NodeNotFound, "未找到逻辑节点");
}

LogicEditorResult LogicEditorService::removeNode(
@@ -604,7 +604,7 @@ LogicEditorResult LogicEditorService::removeNode(
const std::string rung_id = rungIdForNode(logic_id, node_id);
if (rung_id.empty())
{
return failure(LogicEditorError::NodeNotFound, "logic node was not found");
return failure(LogicEditorError::NodeNotFound, "未找到逻辑节点");
}
const LadderRung *rung = findRung(logic_id, rung_id);
if (rung->output.has_value() && rung->output->id == node_id)
@@ -623,7 +623,7 @@ LogicEditorResult LogicEditorService::removeExpression(
{
if (findExpression(logic_id, rung_id, expression_id) == nullptr)
{
return failure(LogicEditorError::ExpressionNotFound, "condition branch was not found");
return failure(LogicEditorError::ExpressionNotFound, "未找到条件支路");
}
Project &project = project_service_.editProject();
LadderRung *rung = findEditableRung(project, logic_id, rung_id);


+ 1
- 1
app/src/services/offline_simulation_service.cpp Ver fichero

@@ -61,7 +61,7 @@ LogicScanResult OfflineSimulationService::executeOnce()
{
return {false,
LogicScanError::InvalidLogic,
"offline simulation is not running",
"离线仿真尚未运行",
{},
{},
{}};


+ 5
- 5
app/src/services/project_service.cpp Ver fichero

@@ -26,7 +26,7 @@ std::string generateProjectId()

ProjectService::ProjectService(ProjectStorage &storage)
: storage_(storage),
project_(makeNewProject("Untitled"))
project_(makeNewProject("未命名工程"))
{
}

@@ -64,7 +64,7 @@ ProjectOperationResult ProjectService::createNewProject(const std::string &name)
return {false,
ProjectServiceError::InvalidProjectName,
ProjectStorageError::None,
"project name must not be empty"};
"工程名称不能为空"};
}

// 新工程创建成功后清除原文件关联,并标记为待保存
@@ -81,7 +81,7 @@ ProjectOperationResult ProjectService::save()
return {false,
ProjectServiceError::FilePathRequired,
ProjectStorageError::None,
"project file path is required"};
"必须指定工程文件路径"};
}
// 复用另存为流程,确保两种保存方式拥有相同的校验和错误处理
return saveAs(current_file_path_);
@@ -94,7 +94,7 @@ ProjectOperationResult ProjectService::saveAs(const std::string &file_path)
return {false,
ProjectServiceError::FilePathRequired,
ProjectStorageError::None,
"project file path is required"};
"必须指定工程文件路径"};
}

std::string validation_error;
@@ -126,7 +126,7 @@ ProjectOperationResult ProjectService::load(const std::string &file_path)
return {false,
ProjectServiceError::FilePathRequired,
ProjectStorageError::None,
"project file path is required"};
"必须指定工程文件路径"};
}

ProjectLoadResult result = storage_.load(file_path);


+ 1
- 1
app/src/services/runtime_mode_service.cpp Ver fichero

@@ -176,7 +176,7 @@ PlcCommunicationResult RuntimeModeService::connectPlc(
{
if (plc_gateway_ == nullptr)
{
return {false, "PLC communication is not configured"};
return {false, "PLC 通信服务尚未配置"};
}
std::vector<RegisterAddress> addresses;
const Project &project = project_service_.project();


+ 10
- 10
app/src/services/software_logic_executor.cpp Ver fichero

@@ -96,7 +96,7 @@ LogicScanResult SoftwareLogicExecutor::validate(
{
return failure(
LogicScanError::InvalidLogic,
"ladder output is not a coil",
"梯形图输出不是线圈节点",
logic.id,
rung.id,
rung.output->id);
@@ -106,7 +106,7 @@ LogicScanResult SoftwareLogicExecutor::validate(
{
return failure(
LogicScanError::ConflictingOutput,
"mixed coil modes target " + output->address.toString(),
"同一地址使用了不同线圈模式:" + output->address.toString(),
logic.id,
rung.id,
rung.output->id);
@@ -180,7 +180,7 @@ LogicScanResult SoftwareLogicExecutor::evaluateExpression(
{
if (value == nullptr)
{
return failure(LogicScanError::InvalidLogic, "expression result target is missing");
return failure(LogicScanError::InvalidLogic, "缺少表达式结果接收对象");
}
if (expression.kind == ConditionExpressionKind::Node)
{
@@ -222,7 +222,7 @@ LogicScanResult SoftwareLogicExecutor::evaluateCondition(
{
return failure(
LogicScanError::InvalidLogic,
"condition result target is missing",
"缺少条件结果接收对象",
{},
{},
node.id);
@@ -239,7 +239,7 @@ LogicScanResult SoftwareLogicExecutor::evaluateCondition(
{
return failure(
LogicScanError::RegisterReadFailed,
"failed to read " + config.address.toString(),
"读取寄存器失败:" + config.address.toString(),
{},
{},
node.id);
@@ -255,7 +255,7 @@ LogicScanResult SoftwareLogicExecutor::evaluateCondition(
{
return failure(
LogicScanError::RegisterReadFailed,
"failed to read " + config.address.toString(),
"读取寄存器失败:" + config.address.toString(),
{},
{},
node.id);
@@ -267,7 +267,7 @@ LogicScanResult SoftwareLogicExecutor::evaluateCondition(
{
return failure(
LogicScanError::InvalidLogic,
"condition node contains an output coil",
"条件节点不能包含输出线圈",
{},
{},
node.id);
@@ -286,7 +286,7 @@ LogicScanResult SoftwareLogicExecutor::writeOutput(
{
return failure(
LogicScanError::InvalidLogic,
"ladder output is not a coil",
"梯形图输出不是线圈节点",
{},
{},
node.id);
@@ -316,7 +316,7 @@ LogicScanResult SoftwareLogicExecutor::writeOutput(
{
return failure(
LogicScanError::InvalidLogic,
"unsupported coil mode",
"不支持的线圈模式",
{},
{},
node.id);
@@ -333,7 +333,7 @@ LogicScanResult SoftwareLogicExecutor::writeOutput(
{
return failure(
LogicScanError::RegisterWriteFailed,
"failed to write " + config->address.toString(),
"写入寄存器失败:" + config->address.toString(),
{},
{},
node.id);


Cargando…
Cancelar
Guardar