diff --git a/.gitignore b/.gitignore index ce63f09..97077be 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ /win_text_editor/web /win_text_editor/windows/runner /cpp_server/swagger +/uft_dev_server/build +/uft_dev_server/third_party diff --git a/CppServerProject b/CppServerProject deleted file mode 160000 index 73cb769..0000000 --- a/CppServerProject +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 73cb76986ce1748eaee5ee6aee9c34a835d52fd5 diff --git a/documents/PB UFT模块迁移方案.docx b/documents/PB UFT模块迁移方案.docx index b353d7b..d67ea65 100644 Binary files a/documents/PB UFT模块迁移方案.docx and b/documents/PB UFT模块迁移方案.docx differ diff --git a/uft_dev_server/CMakeLists.txt b/uft_dev_server/CMakeLists.txt index 74427cd..6b12da0 100644 --- a/uft_dev_server/CMakeLists.txt +++ b/uft_dev_server/CMakeLists.txt @@ -16,11 +16,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # 设置源文件目录 set(SOURCE_DIR src) - -set(RCCPP_SOURCE_DIR third_party/RuntimeCompiledCPlusPlus/Aurora) - -# D:\aigc\Libs\RCCPP\lib -set(RCCPP_LIB_DIR "D:/aigc/Libs/RCCPP/lib") +add_subdirectory(imgui) # 查找依赖包 @@ -45,14 +41,12 @@ add_executable(${PROJECT_NAME} # 链接库 target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon + imgui ${CMAKE_DL_LIBS} # 用于动态加载 - "${RCCPP_LIB_DIR}/RuntimeCompiler.lib" - "${RCCPP_LIB_DIR}/RuntimeObjectSystem.lib" ) # 包含目录 target_include_directories(${PROJECT_NAME} PRIVATE - ${RCCPP_SOURCE_DIR} ${SOURCE_DIR} ${SOURCE_DIR}/controllers ${SOURCE_DIR}/filters diff --git a/uft_dev_server/cmd.txt b/uft_dev_server/cmd.txt index 598335e..c3e483c 100644 --- a/uft_dev_server/cmd.txt +++ b/uft_dev_server/cmd.txt @@ -1,12 +1,4 @@ -#增加RCC++依赖包(专为自行编译RCCPP提供,直接使用已有RCCPP目录则无需执行--注意命令执行位置) -mkdir third_party -git clone https://github.com/RuntimeCompiledCPlusPlus/RuntimeCompiledCPlusPlus.git -cd RuntimeCompiledCPlusPlus/Aurora -rm -Path build -Recurse -Force -mkdir build -cd build -cmake .. -DCMAKE_INSTALL_PREFIX="D:/aigc/Libs/RCCPP" -DINSTALL_CMAKE_CONFIG=ON -DBUILD_SHARED_LIBS=ON -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_VERSION_MINIMUM="4.0.2" -cmake --build . --config Debug --target install + #工程编译 diff --git a/uft_dev_server/rccpp_config.h b/uft_dev_server/rccpp_config.h deleted file mode 100644 index a31473f..0000000 --- a/uft_dev_server/rccpp_config.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#define RCCPPUSER_USE_PRECOMPILED_HEADER 0 -#define RCCPPUSER_USE_EXCEPTIONS 1 -#define RCCPPUSER_USE_RTTI 1 -#define RCCPPUSER_USE_DEBUG_NEW 0 -#define RCCPPUSER_USE_VLD 0 -#define RCCPPUSER_USE_IMGUI 0 \ No newline at end of file diff --git a/uft_dev_server/src/main.cpp b/uft_dev_server/src/main.cpp index 457e0ce..02fc293 100644 --- a/uft_dev_server/src/main.cpp +++ b/uft_dev_server/src/main.cpp @@ -1,27 +1,38 @@ -#include -#include - -using namespace drogon; +#include "imgui.h" +#include "imgui_impl_glfw.h" +#include "imgui_impl_opengl3.h" int main() { - try - { - // 设置日志级别 - drogon::app().setLogLevel(trantor::Logger::kTrace); - drogon::app().registerBeginningAdvice([]() - { LOG_INFO << "Drogon application starting..."; }); + // 初始化窗口和渲染上下文(例如GLFW+OpenGL) + glfwInit(); + GLFWwindow *window = glfwCreateWindow(1280, 720, "ImGui Demo", NULL, NULL); - // 加载配置 - drogon::app().loadConfigFile("./config.json"); + // 初始化ImGui + ImGui::CreateContext(); + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplOpenGL3_Init("#version 130"); - // 启动服务 - drogon::app().run(); - } - catch (const std::exception &e) + while (!glfwWindowShouldClose(window)) { - std::cerr << "Error: " << e.what() << std::endl; - return 1; + // 开始新帧 + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + // 创建UI + ImGui::Begin("Demo Window"); + ImGui::Text("Hello, world!"); + if (ImGui::Button("Save")) + { + // 按钮点击处理 + } + ImGui::End(); + + // 渲染 + ImGui::Render(); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + glfwSwapBuffers(window); } - return 0; } \ No newline at end of file diff --git a/uft_dev_server/src/swagger/swagger.json b/uft_dev_server/src/swagger/swagger.json deleted file mode 100644 index 9e41a03..0000000 --- a/uft_dev_server/src/swagger/swagger.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "openapi": "3.0.0", - "info": { - "title": "CppServerProject API", - "version": "1.0.0", - "description": "A sample C++ backend server with Swagger documentation" - }, - "paths": { - "/hello": { - "get": { - "summary": "Hello World", - "description": "Returns a simple greeting", - "responses": { - "200": { - "description": "Successful response", - "content": { - "text/plain": { - "schema": { - "type": "string", - "example": "Hello, World!" - } - } - } - } - } - } - }, - "/api/info": { - "get": { - "summary": "Get API info", - "description": "Returns basic API information", - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiInfo" - } - } - } - } - } - } - } - }, - "components": { - "schemas": { - "ApiInfo": { - "type": "object", - "properties": { - "status": { - "type": "string" - }, - "version": { - "type": "string" - }, - "message": { - "type": "string" - } - } - } - } - } -} \ No newline at end of file diff --git a/win_text_editor/lib/modules/memory_table/widgets/memory_table_left_side.dart b/win_text_editor/lib/modules/memory_table/widgets/memory_table_left_side.dart index 5a1baa2..e6f62f2 100644 --- a/win_text_editor/lib/modules/memory_table/widgets/memory_table_left_side.dart +++ b/win_text_editor/lib/modules/memory_table/widgets/memory_table_left_side.dart @@ -42,64 +42,56 @@ class MemoryTableLeftSide extends StatelessWidget { Expanded( child: LayoutBuilder( builder: (context, constraints) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SizedBox( - width: constraints.maxWidth > 800 ? constraints.maxWidth : 800, - child: SfDataGrid( - source: fieldsSource, - gridLinesVisibility: GridLinesVisibility.both, - headerGridLinesVisibility: GridLinesVisibility.both, - columnWidthMode: ColumnWidthMode.fitByCellValue, - selectionMode: SelectionMode.none, - columns: [ - GridColumn( - columnName: 'select', - label: ValueListenableBuilder( - valueListenable: fieldsSource.selectionNotifier, - builder: - (context, _, __) => _buildCheckboxHeader(context, fieldsSource), - ), - width: 60, + return SizedBox( + width: constraints.maxWidth, + child: SfDataGrid( + source: fieldsSource, + gridLinesVisibility: GridLinesVisibility.both, + headerGridLinesVisibility: GridLinesVisibility.both, + columnWidthMode: ColumnWidthMode.fitByCellValue, + selectionMode: SelectionMode.none, + columns: [ + GridColumn( + columnName: 'select', + label: ValueListenableBuilder( + valueListenable: fieldsSource.selectionNotifier, + builder: (context, _, __) => _buildCheckboxHeader(context, fieldsSource), ), - GridColumn( - columnName: 'id', - label: _buildGridHeader('序号'), - minimumWidth: 80, - ), - GridColumn( - columnName: 'name', - label: _buildGridHeader('名称'), - minimumWidth: 120, - ), - GridColumn( - columnName: 'chineseName', - label: _buildGridHeader('中文名'), - minimumWidth: 120, - ), - GridColumn( - columnName: 'type', - label: _buildGridHeader('类型'), - minimumWidth: 120, - ), - GridColumn( - columnName: 'remark', - label: _buildGridHeader('备注'), - minimumWidth: 200, - ), - ], - onCellTap: (details) { - if (details.column.columnName == 'select') { - final rowIndex = details.rowColumnIndex.rowIndex - 1; - if (rowIndex >= 0 && rowIndex < fieldsSource.items.length) { - fieldsSource.toggleRowSelection( - rowIndex, - !fieldsSource.items[rowIndex].isSelected, - ); - } + width: 60, + ), + GridColumn(columnName: 'id', label: _buildGridHeader('序号'), minimumWidth: 80), + GridColumn( + columnName: 'name', + label: _buildGridHeader('名称'), + minimumWidth: 120, + ), + GridColumn( + columnName: 'chineseName', + label: _buildGridHeader('中文名'), + minimumWidth: 120, + ), + GridColumn( + columnName: 'type', + label: _buildGridHeader('类型'), + minimumWidth: 120, + ), + GridColumn( + columnName: 'remark', + label: _buildGridHeader('备注'), + minimumWidth: 200, + ), + ], + onCellTap: (details) { + if (details.column.columnName == 'select') { + final rowIndex = details.rowColumnIndex.rowIndex - 1; + if (rowIndex >= 0 && rowIndex < fieldsSource.items.length) { + fieldsSource.toggleRowSelection( + rowIndex, + !fieldsSource.items[rowIndex].isSelected, + ); } - }, - ), + } + }, ), ); }, @@ -142,58 +134,54 @@ class MemoryTableLeftSide extends StatelessWidget { Expanded( child: LayoutBuilder( builder: (context, constraints) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SizedBox( - width: constraints.maxWidth > 800 ? constraints.maxWidth : 800, - child: SfDataGrid( - source: indexesSource, - gridLinesVisibility: GridLinesVisibility.both, - headerGridLinesVisibility: GridLinesVisibility.both, - columnWidthMode: ColumnWidthMode.fitByCellValue, - columns: [ - GridColumn( - columnName: 'select', - label: ValueListenableBuilder( - valueListenable: indexesSource.selectionNotifier, - builder: - (context, _, __) => _buildCheckboxHeader(context, indexesSource), - ), - width: 60, - ), - GridColumn( - columnName: 'indexName', - label: _buildGridHeader('索引名称'), - minimumWidth: 120, - ), - GridColumn( - columnName: 'isPrimary', - label: _buildGridHeader('是否主键'), - minimumWidth: 100, - ), - GridColumn( - columnName: 'indexFields', - label: _buildGridHeader('索引字段'), - minimumWidth: 150, - ), - GridColumn( - columnName: 'rule', - label: _buildGridHeader('规则'), - minimumWidth: 200, + return SizedBox( + width: constraints.maxWidth, + child: SfDataGrid( + source: indexesSource, + gridLinesVisibility: GridLinesVisibility.both, + headerGridLinesVisibility: GridLinesVisibility.both, + columnWidthMode: ColumnWidthMode.fitByCellValue, + columns: [ + GridColumn( + columnName: 'select', + label: ValueListenableBuilder( + valueListenable: indexesSource.selectionNotifier, + builder: (context, _, __) => _buildCheckboxHeader(context, indexesSource), ), - ], - onCellTap: (details) { - if (details.column.columnName == 'select') { - final rowIndex = details.rowColumnIndex.rowIndex - 1; - if (rowIndex >= 0 && rowIndex < indexesSource.items.length) { - indexesSource.toggleRowSelection( - rowIndex, - !indexesSource.items[rowIndex].isSelected, - ); - } + width: 60, + ), + GridColumn( + columnName: 'indexName', + label: _buildGridHeader('索引名称'), + minimumWidth: 120, + ), + GridColumn( + columnName: 'isPrimary', + label: _buildGridHeader('是否主键'), + minimumWidth: 100, + ), + GridColumn( + columnName: 'indexFields', + label: _buildGridHeader('索引字段'), + minimumWidth: 150, + ), + GridColumn( + columnName: 'rule', + label: _buildGridHeader('规则'), + minimumWidth: 200, + ), + ], + onCellTap: (details) { + if (details.column.columnName == 'select') { + final rowIndex = details.rowColumnIndex.rowIndex - 1; + if (rowIndex >= 0 && rowIndex < indexesSource.items.length) { + indexesSource.toggleRowSelection( + rowIndex, + !indexesSource.items[rowIndex].isSelected, + ); } - }, - ), + } + }, ), ); }, diff --git a/win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart b/win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart index af53e62..6dc642d 100644 --- a/win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart +++ b/win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart @@ -13,8 +13,12 @@ class TemplateParserController extends BaseContentController { final FilterController filterController; final GridViewController gridController; + static const String modeByPath = "byPath"; + static const String modeByStruct = "byStruct"; + String _filePath = ''; String? _errorMessage; + String statisticsMode = modeByPath; String get filePath => _filePath; String? get errorMessage => _errorMessage; @@ -51,6 +55,12 @@ class TemplateParserController extends BaseContentController { } //----------------业务入口方法----- + + void setStatisticsMode(String? value) { + statisticsMode = value ?? modeByPath; + notifyListeners(); + } + //widget调用入口:打开文件 Future pickFile() async { final result = await FilePicker.platform.pickFiles( @@ -71,34 +81,27 @@ class TemplateParserController extends BaseContentController { await _loadTemplateData(); } - //加载xml文件 - Future _loadTemplateData() async { - try { - _errorMessage = null; - final file = File(_filePath); - final content = await file.readAsString(); - final document = xml.XmlDocument.parse(content); - - // 更新各控制器 - //树视图展示文件结构 - treeController.updateTreeNodes( - _buildTreeNodes(document.rootElement, document.rootElement.localName, depth: 0), - ); - //列表展示选中节点的内容 - gridController.updateTemplateItems(_parseAllNodeValues(document)); - } catch (e) { - _errorMessage = 'Failed to load XML: ${e.toString()}'; - Logger().error('XML加载错误$_errorMessage'); + List _buildTreeNodes( + xml.XmlElement element, + String path, { + required int depth, + int repeatCount = 1, + }) { + // 根据统计模式决定如何构建节点 + if (statisticsMode == TemplateParserController.modeByStruct) { + return _buildTreeNodesByStructure(element.document!); + } else { + return _buildTreeNodesByPath(element, path, depth: depth, repeatCount: repeatCount); } } //--------------------私有方法--------- // 构建树节点 - List _buildTreeNodes( + List _buildTreeNodesByPath( xml.XmlElement element, String path, { required int depth, - int repreatCount = 1, + int repeatCount = 1, }) { final node = TemplateNode( path: path, @@ -106,8 +109,8 @@ class TemplateParserController extends BaseContentController { children: [], depth: depth, isExpanded: depth < 5, // 默认展开前两层 - isRepeated: repreatCount > 1, - repreatCount: repreatCount, + isRepeated: repeatCount > 1, + repeatCount: repeatCount, ); // 添加当前元素的所有属性节点 @@ -143,7 +146,7 @@ class TemplateParserController extends BaseContentController { } else { // 多个相同节点需要合并 node.children.addAll( - _buildTreeNodes(elements.first, path0, depth: depth + 1, repreatCount: elements.length), + _buildTreeNodes(elements.first, path0, depth: depth + 1, repeatCount: elements.length), ); } }); @@ -151,11 +154,172 @@ class TemplateParserController extends BaseContentController { return [node]; } - //解析全量数据 + List _buildTreeNodesByStructure(xml.XmlDocument document) { + final structureMap = >{}; + + // 收集所有节点并按结构分组 + void collectNodes(xml.XmlElement element) { + final structureKey = _getNodeStructureKey(element); + structureMap.putIfAbsent(structureKey, () => []).add(element); + + // 继续遍历子元素 + for (var child in element.children.whereType()) { + collectNodes(child); + } + } + + collectNodes(document.rootElement); + + // 构建树节点 + return structureMap.entries.map((entry) { + final elements = entry.value; + final firstElement = elements.first; + final nodeName = firstElement.name.local; + final attributes = firstElement.attributes.map((attr) => attr.name.local).toList()..sort(); + + // 构建父节点 + final parentNode = TemplateNode( + path: entry.key, + name: + attributes.isEmpty + ? '$nodeName(${elements.length})' + : '$nodeName(${attributes.join("|")})(${elements.length})', + children: [], + depth: 0, + isExpanded: true, + isRepeated: false, + repeatCount: elements.length, + ); + + // 添加属性节点(仅显示名称) + parentNode.children.addAll( + firstElement.attributes.map( + (attr) => TemplateNode( + path: '${entry.key}/@${attr.name.local}', + name: '@${attr.qualifiedName}', + children: [], + depth: 1, + isAttribute: true, + ), + ), + ); + + // 添加文本内容节点(如果有) + final hasTextContent = firstElement.children.whereType().isNotEmpty; + + if (hasTextContent) { + parentNode.children.add( + TemplateNode( + path: '${entry.key}/#text', + name: '#text', + children: [], + depth: 1, + isTextNode: true, + ), + ); + } + + return parentNode; + }).toList(); + } + + // 获取节点结构标识键(仅节点名和属性名) + String _getNodeStructureKey(xml.XmlElement element) { + final attrNames = element.attributes.map((attr) => attr.name.local).toList()..sort(); + + return '${element.name.local}|${attrNames.join(",")}'; + } + + // 修改 _loadTemplateData 方法 + Future _loadTemplateData() async { + try { + _errorMessage = null; + final file = File(_filePath); + final content = await file.readAsString(); + final document = xml.XmlDocument.parse(content); + + // 更新树视图 + treeController.updateTreeNodes( + statisticsMode == modeByStruct + ? _buildTreeNodesByStructure(document) + : _buildTreeNodesByPath(document.rootElement, document.rootElement.localName, depth: 0), + ); + + // 更新表格数据 + gridController.updateTemplateItems(_parseAllNodeValues(document)); + } catch (e) { + _errorMessage = 'Failed to load XML: ${e.toString()}'; + Logger().error('XML加载错误$_errorMessage'); + } + } + + // 获取节点结构标识符(属性名排序后拼接) List _parseAllNodeValues(xml.XmlDocument document) { final items = []; int id = 0; + // 按结构统计模式的处理逻辑 + if (statisticsMode == modeByStruct) { + final structureMap = >{}; + + // 收集所有节点并按结构分组 + void collectNodes(xml.XmlElement element) { + final structureKey = _getNodeStructureKey(element); + structureMap.putIfAbsent(structureKey, () => []).add(element); + + for (var child in element.children.whereType()) { + collectNodes(child); + } + } + + collectNodes(document.rootElement); + + // 为每个结构组创建数据项 + structureMap.forEach((structureKey, elements) { + final firstElement = elements.first; + final attributes = firstElement.attributes.map((attr) => attr.name.local).toList()..sort(); + int index = 0; + // 添加属性数据项 + for (final attrName in attributes) { + index = 0; + for (final element in elements) { + final attr = element.getAttributeNode(attrName); + if (attr != null) { + index++; + items.add( + TemplateItem( + id: id++, + rowId: "$structureKey/@$index", + xPath: '$structureKey/@$attrName', + value: attr.value, + ), + ); + } + } + } + + // 添加文本内容数据项 + index = 0; + for (final element in elements) { + final textNodes = element.children.whereType(); + if (textNodes.isNotEmpty) { + index++; + items.add( + TemplateItem( + id: id++, + rowId: "$structureKey/$index", + xPath: "$structureKey/#text", + value: textNodes.first.text, + ), + ); + } + } + }); + + return items; + } + + // 按路径统计模式的原始逻辑 void traverse(xml.XmlElement element, String currentPath, int index) { // 处理属性 for (final attr in element.attributes) { @@ -163,10 +327,8 @@ class TemplateParserController extends BaseContentController { TemplateItem( id: id++, rowId: "$currentPath/@$index", - content: attr.value, xPath: '$currentPath/@${attr.name.local}', value: attr.value, - nodeType: NodeType.attribute, ), ); } @@ -178,15 +340,13 @@ class TemplateParserController extends BaseContentController { TemplateItem( id: id++, rowId: "$currentPath/@$index", - content: textNodes.first.text, xPath: currentPath, value: textNodes.first.text, - nodeType: NodeType.text, ), ); } - // 3. 处理子元素(考虑重复元素的情况) + // 处理子元素 final childElements = element.children.whereType(); final groupedChildren = >{}; diff --git a/win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart b/win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart index 45a526a..3e1a763 100644 --- a/win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart +++ b/win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart @@ -69,19 +69,46 @@ class _TemplateParserViewState extends State { Widget _buildFilePathInput() { return Consumer( builder: (context, controller, _) { - return TextField( - decoration: InputDecoration( - labelText: 'XML File', - hintText: 'Select an XML file', - suffixIcon: IconButton( - icon: const Icon(Icons.folder_open), - onPressed: controller.pickFile, + return Row( + children: [ + // 新增统计模式下拉框 + SizedBox( + width: 150, + child: DropdownButtonFormField( + value: 'byPath', // 默认值 + decoration: const InputDecoration( + labelText: '统计模式', + border: OutlineInputBorder(), + contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 12), + ), + items: const [ + DropdownMenuItem(value: 'byPath', child: Text('按节点路径')), + DropdownMenuItem(value: 'byStruct', child: Text('按节点结构')), + ], + onChanged: (value) { + controller.setStatisticsMode(value); + }, + ), ), - border: const OutlineInputBorder(), - errorText: controller.errorMessage, - ), - controller: TextEditingController(text: controller.filePath), - readOnly: true, + const SizedBox(width: 8), + // 原有的文件路径输入框 + Expanded( + child: TextField( + decoration: InputDecoration( + labelText: 'XML File', + hintText: 'Select an XML file', + suffixIcon: IconButton( + icon: const Icon(Icons.folder_open), + onPressed: controller.pickFile, + ), + border: const OutlineInputBorder(), + errorText: controller.errorMessage, + ), + controller: TextEditingController(text: controller.filePath), + readOnly: true, + ), + ), + ], ); }, ); diff --git a/win_text_editor/lib/modules/template_parser/widgets/tree_view.dart b/win_text_editor/lib/modules/template_parser/widgets/tree_view.dart index 87a1f4d..92d4e66 100644 --- a/win_text_editor/lib/modules/template_parser/widgets/tree_view.dart +++ b/win_text_editor/lib/modules/template_parser/widgets/tree_view.dart @@ -77,7 +77,7 @@ class TemplateTreeView extends StatelessWidget { trailing: templateNode.isRepeated ? Text( - "(${templateNode.repreatCount.toString()})", + "(${templateNode.repeatCount.toString()})", style: const TextStyle(color: Colors.grey), ) : null, diff --git a/win_text_editor/lib/shared/models/template_node.dart b/win_text_editor/lib/shared/models/template_node.dart index b10d52d..58c5ce4 100644 --- a/win_text_editor/lib/shared/models/template_node.dart +++ b/win_text_editor/lib/shared/models/template_node.dart @@ -14,8 +14,9 @@ class TemplateNode implements TreeNode { final String path; bool isRepeated; bool isAttribute; - int repreatCount; - bool isChecked; // 新增属性,用于记录节点是否被选中 + int repeatCount; + bool isChecked; + final bool isTextNode; TemplateNode({ required this.name, @@ -25,8 +26,9 @@ class TemplateNode implements TreeNode { this.isExpanded = false, this.isRepeated = false, this.isAttribute = false, - this.repreatCount = 1, - this.isChecked = false, // 初始化默认未选中 + this.repeatCount = 1, + this.isChecked = false, + this.isTextNode = false, }); @override @@ -44,21 +46,8 @@ enum NodeType { element, attribute, text } class TemplateItem { final int id; final String rowId; - final String content; final String xPath; final String value; - final NodeType nodeType; - TemplateItem({ - required this.id, - required this.rowId, - required this.content, - required this.xPath, - required this.value, - required this.nodeType, - }); - - bool matchesPath(String path) { - return xPath == path; - } + TemplateItem({required this.id, required this.rowId, required this.xPath, required this.value}); }