|
|
|
@ -3,6 +3,8 @@ import 'package:provider/provider.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 {
@@ -13,9 +15,73 @@ class TemplateGridView extends StatelessWidget {
|
|
|
|
|
Widget build(BuildContext context) { |
|
|
|
|
return Consumer<TemplateParserController>( |
|
|
|
|
builder: (context, controller, _) { |
|
|
|
|
return _buildGridView(controller.templateItems, controller); |
|
|
|
|
return GestureDetector( |
|
|
|
|
onSecondaryTapDown: (details) { |
|
|
|
|
_showContextMenu(context, details.globalPosition, controller); |
|
|
|
|
}, |
|
|
|
|
child: _buildGridView(controller.templateItems, controller), |
|
|
|
|
); |
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Future<void> _showContextMenu( |
|
|
|
|
BuildContext context, |
|
|
|
|
Offset position, |
|
|
|
|
TemplateParserController controller, |
|
|
|
|
) async { |
|
|
|
|
// 获取渲染对象以正确定位菜单 |
|
|
|
|
final renderBox = context.findRenderObject() as RenderBox; |
|
|
|
|
final localPosition = renderBox.globalToLocal(position); |
|
|
|
|
|
|
|
|
|
// 显示菜单并等待选择结果 |
|
|
|
|
final result = await showMenu<String>( |
|
|
|
|
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<String>(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<void> _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<TemplateItem> items, TemplateParserController controller) { |
|
|
|
|