From 1a4e5d133209a5418be45567d183a98fbc9630e1 Mon Sep 17 00:00:00 2001 From: hejl Date: Tue, 20 May 2025 16:48:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BDOK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../widgets/template_grid_view.dart | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/win_text_editor/lib/modules/template_parser/widgets/template_grid_view.dart b/win_text_editor/lib/modules/template_parser/widgets/template_grid_view.dart index e5d902c..047acc2 100644 --- a/win_text_editor/lib/modules/template_parser/widgets/template_grid_view.dart +++ b/win_text_editor/lib/modules/template_parser/widgets/template_grid_view.dart @@ -3,6 +3,8 @@ import 'package:provider/provider.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:win_text_editor/modules/template_parser/controllers/template_parser_controller.dart'; import 'package:win_text_editor/modules/template_parser/models/template_node.dart'; +import 'package:file_picker/file_picker.dart'; +import 'dart:io'; class TemplateGridView extends StatelessWidget { final TemplateParserController controller; @@ -13,9 +15,73 @@ class TemplateGridView extends StatelessWidget { Widget build(BuildContext context) { return Consumer( builder: (context, controller, _) { - return _buildGridView(controller.templateItems, controller); + return GestureDetector( + onSecondaryTapDown: (details) { + _showContextMenu(context, details.globalPosition, controller); }, + child: _buildGridView(controller.templateItems, controller), ); + }, + ); + } + + Future _showContextMenu( + BuildContext context, + Offset position, + TemplateParserController controller, + ) async { + // 获取渲染对象以正确定位菜单 + final renderBox = context.findRenderObject() as RenderBox; + final localPosition = renderBox.globalToLocal(position); + + // 显示菜单并等待选择结果 + final result = await showMenu( + context: context, + position: RelativeRect.fromLTRB( + position.dx, + position.dy, + position.dx + renderBox.size.width - localPosition.dx, + position.dy + renderBox.size.height - localPosition.dy, + ), + items: [const PopupMenuItem(value: 'export', child: Text('导出(csv)'))], + ); + + // 处理菜单选择结果 + if (result == 'export' && context.mounted) { + try { + await _exportToCsv(controller); + } catch (e) { + if (context.mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('导出失败: ${e.toString()}'))); + } + } + } + } + + Future _exportToCsv(TemplateParserController controller) async { + String csvData = '序号\t内容\n'; + final filteredItems = + controller.selectedNode != null + ? controller.templateItems.where((item) => item.matchesPath(controller.selectedNode!.path)).toList() + : controller.templateItems; + + for (var item in filteredItems) { + csvData += '${filteredItems.indexOf(item) + 1}\t${item.value}\n'; + } + + final filePath = await FilePicker.platform.saveFile( + dialogTitle: '保存导出结果', + fileName: 'template_results.csv', + type: FileType.custom, + allowedExtensions: ['csv'], + ); + + if (filePath != null) { + final file = File(filePath); + await file.writeAsString(csvData); + } } Widget _buildGridView(List items, TemplateParserController controller) {