From 6e76a95c06f66354a9935a84817801afdff2d11c Mon Sep 17 00:00:00 2001 From: hejl Date: Fri, 23 May 2025 09:25:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=81=9A=E4=BA=86=E4=B8=AAdemo=E7=A9=BA?= =?UTF-8?q?=E7=AA=97=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- documents/PB UFT模块迁移方案.docx | Bin 417883 -> 417926 bytes win_text_editor/lib/menus/app_menu.dart | 5 +- win_text_editor/lib/menus/menu_actions.dart | 139 +++++++++--------- win_text_editor/lib/menus/menu_constants.dart | 2 + .../content_search_controller.dart | 1 - .../controllers/data_compare_controller.dart | 13 ++ .../widgets/data_compare_view.dart | 41 ++++++ .../demo/controllers/demo_controller.dart | 13 ++ .../lib/modules/demo/widgets/demo_view.dart | 41 ++++++ .../lib/modules/module_router.dart | 10 ++ 10 files changed, 193 insertions(+), 72 deletions(-) create mode 100644 win_text_editor/lib/modules/data_compare/controllers/data_compare_controller.dart create mode 100644 win_text_editor/lib/modules/data_compare/widgets/data_compare_view.dart create mode 100644 win_text_editor/lib/modules/demo/controllers/demo_controller.dart create mode 100644 win_text_editor/lib/modules/demo/widgets/demo_view.dart diff --git a/documents/PB UFT模块迁移方案.docx b/documents/PB UFT模块迁移方案.docx index e378b76b2bcc4cdf3568a91d0a0890a0cb9caa28..d11e08fe6a605b7fca2f844a2bb4d6c9e41c298c 100644 GIT binary patch delta 7821 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 F{vVW24V(Y~ delta 7795 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 diff --git a/win_text_editor/lib/menus/app_menu.dart b/win_text_editor/lib/menus/app_menu.dart index 09480bb..fdacc98 100644 --- a/win_text_editor/lib/menus/app_menu.dart +++ b/win_text_editor/lib/menus/app_menu.dart @@ -27,7 +27,10 @@ class AppMenu extends StatelessWidget { return [ const PopupMenuItem(value: MenuConstants.templateParser, child: Text('XML解析')), const PopupMenuItem(value: MenuConstants.contentSearch, child: Text('内容搜索')), - const PopupMenuItem(value: MenuConstants.dataFormat, child: Text('格式化')), + const PopupMenuItem(value: MenuConstants.dataCompare, child: Text('数据对比')), + const PopupMenuItem(value: MenuConstants.dataFormat, child: Text('数据格式化')), + const PopupMenuDivider(), + const PopupMenuItem(value: MenuConstants.demo, child: Text('Demo')), ]; } diff --git a/win_text_editor/lib/menus/menu_actions.dart b/win_text_editor/lib/menus/menu_actions.dart index 817cbb4..f4e7b84 100644 --- a/win_text_editor/lib/menus/menu_actions.dart +++ b/win_text_editor/lib/menus/menu_actions.dart @@ -10,96 +10,95 @@ import 'dart:io'; import 'package:win_text_editor/modules/module_router.dart'; class MenuActions { + static final Map _actionHandlers = { + MenuConstants.openFolder: _openFolder, + MenuConstants.contentSearch: _openContentSearch, + MenuConstants.templateParser: _openTemplateParser, + MenuConstants.dataFormat: _dataFormat, + MenuConstants.dataCompare: _dataCompare, + MenuConstants.demo: _demo, + MenuConstants.exit: _exitApplication, + }; + static Future handleMenuAction(String value, BuildContext context) async { - switch (value) { - case MenuConstants.openFolder: - await _openFolder(context); - break; - case MenuConstants.contentSearch: // 新增内容搜索菜单项 - await _openContentSearch(context); - break; - case MenuConstants.templateParser: - await _openTemplateParser(context); - break; - case MenuConstants.dataFormat: - await _dataFormat(context); - break; - case MenuConstants.exit: - _exitApplication(); - break; - // 其他菜单项可以在这里添加处理逻辑 + final handler = _actionHandlers[value]; + if (handler != null) { + await handler(context); } } static Future _openFolder(BuildContext context) async { - final fileProvider = Provider.of(context, listen: false); - final String? selectedDirectory = await FilePicker.platform.getDirectoryPath(); - - if (selectedDirectory != null) { - await fileProvider.loadDirectory(selectedDirectory); + try { + final fileProvider = Provider.of(context, listen: false); + final String? selectedDirectory = await FilePicker.platform.getDirectoryPath(); + if (selectedDirectory != null) { + await fileProvider.loadDirectory(selectedDirectory); + } + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('打开文件夹失败: $e'))); } } static Future _openContentSearch(BuildContext context) async { - final tabManager = Provider.of(context, listen: false); - - // Create new tab with unique ID - final tabId = DateTime.now().millisecondsSinceEpoch.toString(); - - await tabManager.addTab( - tabId, - title: "内容搜索", - type: RouterKey.contentSearch, - icon: Icons.search, - content: "", - ); + await _openOrActivateTab(context, "内容搜索", RouterKey.contentSearch, Icons.search); } static Future _openTemplateParser(BuildContext context) async { - final tabManager = Provider.of(context, listen: false); + await _openOrActivateTab(context, "XML解析", RouterKey.templateParser, Icons.auto_awesome_mosaic); + } - // 使用 firstWhereOrNull 查找选项卡 - final existingTab = tabManager.tabs.firstWhereOrNull( - (tab) => tab.type == RouterKey.templateParser, - ); + static Future _dataFormat(BuildContext context) async { + await _openOrActivateTab(context, "数据格式化", RouterKey.dataFormat, Icons.date_range); + } - if (existingTab != null) { - // 如果存在,激活该选项卡 - tabManager.setActiveTab(existingTab.id); - } else { - final tabId = DateTime.now().millisecondsSinceEpoch.toString(); - await tabManager.addTab( - tabId, - title: "XML解析", - type: RouterKey.templateParser, - icon: Icons.auto_awesome_mosaic, - content: "", - ); - } + static Future _dataCompare(BuildContext context) async { + await _openOrActivateTab(context, "数据对比", RouterKey.dataCompare, Icons.compare); } - static Future _dataFormat(BuildContext context) async { - final tabManager = Provider.of(context, listen: false); + static Future _demo(BuildContext context) async { + await _openOrActivateTab(context, "Demo", RouterKey.demo, Icons.code); + } - // 使用 firstWhereOrNull 查找选项卡 - final existingTab = tabManager.tabs.firstWhereOrNull((tab) => tab.type == RouterKey.dataFormat); + static Future _openOrActivateTab( + BuildContext context, + String title, + String type, + IconData icon, + ) async { + try { + final tabManager = Provider.of(context, listen: false); + final existingTab = tabManager.tabs.firstWhereOrNull((tab) => tab.type == type); - if (existingTab != null) { - // 如果存在,激活该选项卡 - tabManager.setActiveTab(existingTab.id); - } else { - final tabId = DateTime.now().millisecondsSinceEpoch.toString(); - await tabManager.addTab( - tabId, - title: "数据格式化", - type: RouterKey.dataFormat, - icon: Icons.date_range, - content: "", - ); + if (existingTab != null) { + tabManager.setActiveTab(existingTab.id); + } else { + final tabId = DateTime.now().millisecondsSinceEpoch.toString(); + await tabManager.addTab(tabId, title: title, type: type, icon: icon, content: ""); + } + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('打开标签页失败: $e'))); } } - static void _exitApplication() { - exit(0); + static Future _exitApplication(BuildContext context) async { + final shouldExit = await showDialog( + context: context, + builder: + (context) => AlertDialog( + title: const Text('退出应用'), + content: const Text('确定要退出吗?未保存的内容可能会丢失。'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('取消'), + ), + TextButton(onPressed: () => Navigator.of(context).pop(true), child: const Text('退出')), + ], + ), + ); + + if (shouldExit ?? false) { + exit(0); + } } } diff --git a/win_text_editor/lib/menus/menu_constants.dart b/win_text_editor/lib/menus/menu_constants.dart index a2ef800..6d2ff66 100644 --- a/win_text_editor/lib/menus/menu_constants.dart +++ b/win_text_editor/lib/menus/menu_constants.dart @@ -16,6 +16,8 @@ class MenuConstants { static const String contentSearch = "content_search"; static const String templateParser = 'template_parser'; static const String dataFormat = 'data_format'; + static const String dataCompare = 'data_compare'; + static const String demo = 'demo'; // 编辑菜单项 static const String undo = 'undo'; diff --git a/win_text_editor/lib/modules/content_search/controllers/content_search_controller.dart b/win_text_editor/lib/modules/content_search/controllers/content_search_controller.dart index 34f3ff5..dcedae1 100644 --- a/win_text_editor/lib/modules/content_search/controllers/content_search_controller.dart +++ b/win_text_editor/lib/modules/content_search/controllers/content_search_controller.dart @@ -4,7 +4,6 @@ import 'dart:async'; import 'dart:io'; import 'package:file_picker/file_picker.dart'; -import 'package:flutter/material.dart'; import 'package:win_text_editor/framework/controllers/logger.dart'; import 'package:win_text_editor/modules/content_search/models/search_mode.dart'; import 'package:win_text_editor/modules/content_search/models/search_result.dart'; diff --git a/win_text_editor/lib/modules/data_compare/controllers/data_compare_controller.dart b/win_text_editor/lib/modules/data_compare/controllers/data_compare_controller.dart new file mode 100644 index 0000000..b313900 --- /dev/null +++ b/win_text_editor/lib/modules/data_compare/controllers/data_compare_controller.dart @@ -0,0 +1,13 @@ +import 'package:win_text_editor/shared/base/base_content_controller.dart'; + +class DataCompareController extends BaseContentController { + @override + void onOpenFile(String filePath) { + // TODO: implement onOpenFile + } + + @override + void onOpenFolder(String folderPath) { + // TODO: implement onOpenFolder + } +} diff --git a/win_text_editor/lib/modules/data_compare/widgets/data_compare_view.dart b/win_text_editor/lib/modules/data_compare/widgets/data_compare_view.dart new file mode 100644 index 0000000..b5fa5c0 --- /dev/null +++ b/win_text_editor/lib/modules/data_compare/widgets/data_compare_view.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:win_text_editor/framework/controllers/tab_items_controller.dart'; +import 'package:win_text_editor/modules/data_compare/controllers/data_compare_controller.dart'; + +class DataCompareView extends StatefulWidget { + final String tabId; + const DataCompareView({super.key, required this.tabId}); + + @override + State createState() => _DataCompareViewState(); +} + +class _DataCompareViewState extends State { + late final DataCompareController _controller; + + get tabManager => Provider.of(context, listen: false); + + @override + void initState() { + super.initState(); + _controller = tabManager.getController(widget.tabId) ?? DataCompareController(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider.value( + value: _controller, + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Column(children: [Expanded(flex: 1, child: Text("空白"))]), + ), + ); + } +} diff --git a/win_text_editor/lib/modules/demo/controllers/demo_controller.dart b/win_text_editor/lib/modules/demo/controllers/demo_controller.dart new file mode 100644 index 0000000..c7a3623 --- /dev/null +++ b/win_text_editor/lib/modules/demo/controllers/demo_controller.dart @@ -0,0 +1,13 @@ +import 'package:win_text_editor/shared/base/base_content_controller.dart'; + +class DemoController extends BaseContentController { + @override + void onOpenFile(String filePath) { + // TODO: implement onOpenFile + } + + @override + void onOpenFolder(String folderPath) { + // TODO: implement onOpenFolder + } +} diff --git a/win_text_editor/lib/modules/demo/widgets/demo_view.dart b/win_text_editor/lib/modules/demo/widgets/demo_view.dart new file mode 100644 index 0000000..dc706cc --- /dev/null +++ b/win_text_editor/lib/modules/demo/widgets/demo_view.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:win_text_editor/framework/controllers/tab_items_controller.dart'; +import 'package:win_text_editor/modules/demo/controllers/demo_controller.dart'; + +class DemoView extends StatefulWidget { + final String tabId; + const DemoView({super.key, required this.tabId}); + + @override + State createState() => _DemoViewState(); +} + +class _DemoViewState extends State { + late final DemoController _controller; + + get tabManager => Provider.of(context, listen: false); + + @override + void initState() { + super.initState(); + _controller = tabManager.getController(widget.tabId) ?? DemoController(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider.value( + value: _controller, + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Column(children: [Expanded(flex: 1, child: Text("Demo,就是一个空窗体,用于新增菜单时快速初始化(拷贝)。"))]), + ), + ); + } +} diff --git a/win_text_editor/lib/modules/module_router.dart b/win_text_editor/lib/modules/module_router.dart index 1304d7c..38e86ec 100644 --- a/win_text_editor/lib/modules/module_router.dart +++ b/win_text_editor/lib/modules/module_router.dart @@ -1,8 +1,12 @@ // modules/tab_content_registry.dart import 'package:flutter/material.dart'; import 'package:win_text_editor/framework/models/tab_model.dart'; +import 'package:win_text_editor/modules/data_compare/controllers/data_compare_controller.dart'; +import 'package:win_text_editor/modules/data_compare/widgets/data_compare_view.dart'; import 'package:win_text_editor/modules/data_format/controllers/data_format_controller.dart'; import 'package:win_text_editor/modules/data_format/widgets/data_format_view.dart'; +import 'package:win_text_editor/modules/demo/controllers/demo_controller.dart'; +import 'package:win_text_editor/modules/demo/widgets/demo_view.dart'; import 'package:win_text_editor/shared/base/base_content_controller.dart'; import 'package:win_text_editor/modules/content_search/controllers/content_search_controller.dart'; import 'package:win_text_editor/modules/template_parser/controllers/template_parser_controller.dart'; @@ -14,6 +18,8 @@ class RouterKey { static const String templateParser = 'template_parser'; static const String dataFormat = 'data_format'; static const String textEditor = 'text_editor'; + static const String dataCompare = 'data_compare'; + static const String demo = 'demo'; } class ModuleRouter { @@ -22,6 +28,8 @@ class ModuleRouter { RouterKey.contentSearch: (tab) => ContentSearchController(), RouterKey.templateParser: (tab) => TemplateParserController(), RouterKey.dataFormat: (tab) => DataFormatController(), + RouterKey.dataCompare: (tab) => DataCompareController(), + RouterKey.demo: (tab) => DemoController(), }; // 映射UI组件 @@ -29,6 +37,8 @@ class ModuleRouter { RouterKey.contentSearch: (tab, controller) => ContentSearchView(tabId: tab.id), RouterKey.templateParser: (tab, controller) => TemplateParserView(tabId: tab.id), RouterKey.dataFormat: (tab, controller) => DataFormatView(tabId: tab.id), + RouterKey.dataCompare: (tab, controller) => DataCompareView(tabId: tab.id), + RouterKey.demo: (tab, controller) => DemoView(tabId: tab.id), }; static BaseContentController? createControllerForTab(AppTab tab) {