feature/FCStd模板保存命令-zwl-0520

dev
Zhaowenlong 6 days ago
parent 8831112b8c
commit 0ea8998070

@ -573,4 +573,5 @@ ManualWiring.py
- 2026-05-20明确 A 方案STEP/STP/STE 只作为原始几何输入,正式可复用设备资源统一保存为带 LCS 电气端子的 FCStd 模板;后续设计 `TemplateAuthoring.py` 做模板制作工具。 - 2026-05-20明确 A 方案STEP/STP/STE 只作为原始几何输入,正式可复用设备资源统一保存为带 LCS 电气端子的 FCStd 模板;后续设计 `TemplateAuthoring.py` 做模板制作工具。
- 2026-05-20新增 FCStd 设备模板制作基础能力,支持把模型上的点位创建为带 `Role="Terminal"`、`CanWire=true`、`QetTemplateSlotName` 的模板端子 LCS已用单元测试验证端子语义写入和模板校验逻辑。 - 2026-05-20新增 FCStd 设备模板制作基础能力,支持把模型上的点位创建为带 `Role="Terminal"`、`CanWire=true`、`QetTemplateSlotName` 的模板端子 LCS已用单元测试验证端子语义写入和模板校验逻辑。
- 2026-05-20补充 A 方案资产流转设计,明确 `.FCStd` 为正式设备资产zwl/QET 只负责选择、保存、导出 `.FCStd` 路径FreeCADExchange 负责读取 LCS 端子语义并生成工程端子。 - 2026-05-20补充 A 方案资产流转设计,明确 `.FCStd` 为正式设备资产zwl/QET 只负责选择、保存、导出 `.FCStd` 路径FreeCADExchange 负责读取 LCS 端子语义并生成工程端子。
- 2026-05-20补上 `QET_Template_SaveAsFCStd` 模板保存命令,保存前会校验至少存在一个有效模板端子,并自动补 `.FCStd` 后缀;已用单元测试验证保存路径和端子校验结果。
``` ```

@ -7,6 +7,17 @@ try:
except ImportError: except ImportError:
Gui = None Gui = None
try:
from PySide6 import QtWidgets
except ImportError:
try:
from PySide2 import QtWidgets
except ImportError:
try:
from PySide import QtGui as QtWidgets
except ImportError:
QtWidgets = None
import TerminalObjects import TerminalObjects
@ -151,6 +162,35 @@ def validate_template_terminals(doc):
return report return report
def _fcstd_path(path):
value = (path or "").strip()
if not value:
raise TemplateAuthoringError("A target FCStd path is required.")
if not value.lower().endswith(".fcstd"):
value = value + ".FCStd"
return value
def save_template_as_fcstd(doc, path):
if doc is None:
raise TemplateAuthoringError("An active FreeCAD document is required.")
target_path = _fcstd_path(path)
report = validate_template_terminals(doc)
if report["total_terminals"] <= 0:
raise TemplateAuthoringError("At least one template terminal is required before saving.")
if report["warnings"]:
raise TemplateAuthoringError(
"Template terminals must be valid before saving: {0}".format(
"; ".join(report["warnings"])
)
)
doc.saveAs(target_path)
report["path"] = target_path
return report
def _selection_position(): def _selection_position():
if Gui is None: if Gui is None:
return None return None
@ -236,6 +276,44 @@ class CommandValidateTemplateTerminals:
App.Console.PrintWarning("[FreeCADExchange] {0}\n".format(warning)) App.Console.PrintWarning("[FreeCADExchange] {0}\n".format(warning))
class CommandSaveTemplateAsFCStd:
def GetResources(self):
return {
"MenuText": "Save Template As FCStd",
"ToolTip": "Validate and save the current document as a reusable FCStd equipment template",
}
def IsActive(self):
return App.ActiveDocument is not None
def Activated(self):
if QtWidgets is None:
App.Console.PrintError("[FreeCADExchange] Qt file dialog is not available.\n")
return
file_path, _selected_filter = QtWidgets.QFileDialog.getSaveFileName(
None,
"Save FCStd Equipment Template",
"",
"FreeCAD template (*.FCStd *.fcstd);;All files (*.*)",
)
if not file_path:
return
try:
report = save_template_as_fcstd(App.ActiveDocument, file_path)
App.Console.PrintMessage(
"[FreeCADExchange] Saved FCStd template: {0} ({1} terminals)\n".format(
report["path"],
report["valid_terminals"],
)
)
except Exception as exc:
App.Console.PrintError(
"[FreeCADExchange] template save failed: {0}\n".format(exc)
)
_COMMANDS_REGISTERED = False _COMMANDS_REGISTERED = False
@ -247,6 +325,7 @@ def register_commands():
return return
Gui.addCommand("QET_Template_AddTerminal", CommandAddTemplateTerminal()) Gui.addCommand("QET_Template_AddTerminal", CommandAddTemplateTerminal())
Gui.addCommand("QET_Template_ValidateTerminals", CommandValidateTemplateTerminals()) Gui.addCommand("QET_Template_ValidateTerminals", CommandValidateTemplateTerminals())
Gui.addCommand("QET_Template_SaveAsFCStd", CommandSaveTemplateAsFCStd())
_COMMANDS_REGISTERED = True _COMMANDS_REGISTERED = True

@ -88,6 +88,7 @@ class FakeDocument:
self.Name = "TemplateDoc" self.Name = "TemplateDoc"
self.Objects = [] self.Objects = []
self.recomputed = False self.recomputed = False
self.saved_path = ""
def addObject(self, type_name, name): def addObject(self, type_name, name):
obj = FakeObject(name, type_name) obj = FakeObject(name, type_name)
@ -103,6 +104,9 @@ class FakeDocument:
def recompute(self): def recompute(self):
self.recomputed = True self.recomputed = True
def saveAs(self, path):
self.saved_path = path
def _reload_modules(): def _reload_modules():
for name in ["TerminalObjects", "TemplateAuthoring"]: for name in ["TerminalObjects", "TemplateAuthoring"]:
@ -158,6 +162,19 @@ class TemplateAuthoringTest(unittest.TestCase):
self.assertEqual(1, len(report["warnings"])) self.assertEqual(1, len(report["warnings"]))
self.assertIn("QetTemplateSlotName", report["warnings"][0]) self.assertIn("QetTemplateSlotName", report["warnings"][0])
def test_save_template_as_fcstd_adds_extension_and_saves_valid_template(self):
_install_fake_freecad()
template_authoring = _reload_modules()
app = sys.modules["FreeCAD"]
doc = FakeDocument()
template_authoring.create_template_terminal(doc, "P1", app.Vector(1, 2, 3))
report = template_authoring.save_template_as_fcstd(doc, "D:/tmp/current-transformer")
self.assertEqual("D:/tmp/current-transformer.FCStd", doc.saved_path)
self.assertEqual("D:/tmp/current-transformer.FCStd", report["path"])
self.assertEqual(1, report["valid_terminals"])
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

Loading…
Cancel
Save