Browse Source

模板解析OK

master
hejl 2 months ago
parent
commit
4ffb5f39f9
  1. 252
      win_text_editor/lib/modules/template_parser/widgets/template_grid_view.dart

252
win_text_editor/lib/modules/template_parser/widgets/template_grid_view.dart

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:win_text_editor/framework/controllers/logger.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';
@ -18,9 +19,9 @@ class TemplateGridView extends StatelessWidget { @@ -18,9 +19,9 @@ class TemplateGridView extends StatelessWidget {
return GestureDetector(
onSecondaryTapDown: (details) {
_showContextMenu(context, details.globalPosition, controller);
},
child: _buildGridView(controller.templateItems, controller),
);
},
child: _buildGridView(controller),
);
},
);
}
@ -30,11 +31,9 @@ class TemplateGridView extends StatelessWidget { @@ -30,11 +31,9 @@ class TemplateGridView extends StatelessWidget {
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(
@ -46,7 +45,6 @@ class TemplateGridView extends StatelessWidget { @@ -46,7 +45,6 @@ class TemplateGridView extends StatelessWidget {
items: [const PopupMenuItem<String>(value: 'export', child: Text('导出(csv)'))],
);
//
if (result == 'export' && context.mounted) {
try {
await _exportToCsv(controller);
@ -56,29 +54,30 @@ class TemplateGridView extends StatelessWidget { @@ -56,29 +54,30 @@ class TemplateGridView extends StatelessWidget {
context,
).showSnackBar(SnackBar(content: Text('导出失败: ${e.toString()}')));
}
}
}
}
}
Future<void> _exportToCsv(TemplateParserController controller) async {
String csvData = '序号\t';
final selectedNodes = controller.getSelectedNodes();
for (var node in selectedNodes) {
csvData += '${node.name}\t';
}
if (selectedNodes.isEmpty) return;
//
String csvData = '序号\t';
csvData += selectedNodes.map((node) => node.name).join('\t');
csvData += '\n';
final filteredItems =
controller.selectedNode != null
? controller.templateItems.where((item) => item.matchesPath(controller.selectedNode!.path)).toList()
: controller.templateItems;
//
final rows = _getGroupedData(controller);
for (var item in filteredItems) {
csvData += '${filteredItems.indexOf(item) + 1}\t';
for (var node in selectedNodes) {
//
csvData += '\t';
}
//
for (var i = 0; i < rows.length; i++) {
csvData += '${i + 1}\t';
csvData += selectedNodes
.map((node) {
return rows[i][node.path] ?? '';
})
.join('\t');
csvData += '\n';
}
@ -90,50 +89,49 @@ class TemplateGridView extends StatelessWidget { @@ -90,50 +89,49 @@ class TemplateGridView extends StatelessWidget {
);
if (filePath != null) {
final file = File(filePath);
await file.writeAsString(csvData);
await File(filePath).writeAsString(csvData);
}
}
Widget _buildGridView(List<TemplateItem> items, TemplateParserController controller) {
final filteredItems =
controller.selectedNode != null
? items.where((item) => item.matchesPath(controller.selectedNode!.path)).toList()
: items;
Widget _buildGridView(TemplateParserController controller) {
final selectedNodes = controller.getSelectedNodes();
final dataSource = _TemplateItemDataSource(
items: filteredItems,
selectedNodes: selectedNodes,
);
if (selectedNodes.isEmpty) {
return const Center(child: Text('请在左侧树中选择要显示的节点(勾选复选框)'));
}
List<GridColumn> columns = [
GridColumn(
columnName: 'index',
width: 60,
label: Container(
padding: const EdgeInsets.all(8.0),
color: Colors.grey[200],
alignment: Alignment.center,
child: const Text('序号'),
),
),
];
//
final allItems = controller.templateItems;
// -
final rows = _buildDataRows(selectedNodes, allItems);
final dataSource = _TemplateItemDataSource(rows: rows, selectedNodes: selectedNodes);
for (var node in selectedNodes) {
columns.add(
GridColumn(
columnName: node.id.toString(),
//
final columns = <GridColumn>[
GridColumn(
columnName: 'index',
width: 60,
label: Container(
padding: const EdgeInsets.all(8.0),
color: Colors.grey[200],
alignment: Alignment.center,
child: const Text('序号'),
),
),
...selectedNodes.map((node) {
return GridColumn(
columnName: node.path,
label: Container(
padding: const EdgeInsets.all(8.0),
alignment: Alignment.center,
color: Colors.grey[200],
child: Text(node.name),
child: Text(node.isAttribute ? node.name.substring(1) : node.name),
),
),
);
}
);
}).toList(),
];
return SfDataGrid(
source: dataSource,
@ -143,28 +141,148 @@ class TemplateGridView extends StatelessWidget { @@ -143,28 +141,148 @@ class TemplateGridView extends StatelessWidget {
columnWidthMode: ColumnWidthMode.fill,
);
}
List<Map<String, dynamic>> _buildDataRows(
List<TemplateNode> selectedNodes,
List<TemplateItem> allItems,
) {
// 1.
final nodeValueGroups = <String, List<MapEntry<int, String>>>{};
for (final node in selectedNodes) {
//
final valuesWithIndex =
allItems
.asMap()
.entries
.where((entry) => entry.value.xPath == node.path)
.map((entry) => MapEntry(entry.key, entry.value.value))
.toList();
nodeValueGroups[node.path] = valuesWithIndex;
}
// 2.
final maxRows = nodeValueGroups.values.fold(
0,
(max, group) => group.length > max ? group.length : max,
);
// 3.
final rows = <Map<String, dynamic>>[];
for (var rowIndex = 0; rowIndex < maxRows; rowIndex++) {
final row = <String, dynamic>{'_index': rowIndex + 1};
//
for (final node in selectedNodes) {
final values = nodeValueGroups[node.path]!;
row[node.path] = rowIndex < values.length ? values[rowIndex].value : '';
}
rows.add(row);
}
return rows;
}
List<String> _getInstancesForParent(String parentPath, List<TemplateItem> items) {
//
return items
.where((item) => item.xPath.startsWith(parentPath))
.map((item) {
//
if (parentPath.contains('[')) {
return item.xPath.substring(0, item.xPath.indexOf('/', parentPath.length));
}
return parentPath;
})
.toSet()
.toList();
}
//
List<Map<String, String>> _getGroupedData(TemplateParserController controller) {
final selectedNodes = controller.getSelectedNodes();
if (selectedNodes.isEmpty) return [];
//
final allItems =
controller.templateItems.where((item) {
return selectedNodes.any((node) => item.xPath == node.path);
}).toList();
//
final parentPaths =
selectedNodes.map((node) {
return node.path.substring(0, node.path.lastIndexOf('/'));
}).toSet();
final groupedData = <Map<String, String>>[];
for (final parentPath in parentPaths) {
//
final items =
allItems.where((item) {
return item.xPath.startsWith(parentPath) ||
item.xPath == parentPath ||
(item.xPath.contains('@') &&
item.xPath.substring(0, item.xPath.lastIndexOf('@')) == parentPath);
}).toList();
//
final instanceGroups = <String, Map<String, String>>{};
for (final item in items) {
//
final instanceId = _getInstanceId(item.xPath, parentPath);
if (!instanceGroups.containsKey(instanceId)) {
instanceGroups[instanceId] = {'_parent': parentPath};
}
instanceGroups[instanceId]![item.xPath] = item.value;
}
groupedData.addAll(instanceGroups.values);
}
return groupedData;
}
String _getInstanceId(String fullPath, String parentPath) {
// 使ID
return fullPath.substring(parentPath.length);
}
}
class _TemplateItemDataSource extends DataGridSource {
final List<TemplateItem> items;
final List<Map<String, dynamic>> _rows;
final List<TemplateNode> selectedNodes;
_TemplateItemDataSource({required this.items, required this.selectedNodes});
_TemplateItemDataSource({required List<Map<String, dynamic>> rows, required this.selectedNodes})
: _rows = rows;
@override
List<DataGridRow> get rows =>
items.map((item) {
List<DataGridCell> cells = [
DataGridCell<int>(columnName: 'index', value: items.indexOf(item) + 1),
];
for (var node in selectedNodes) {
//
cells.add(DataGridCell<String>(columnName: node.id.toString(), value: ''));
}
List<DataGridRow> get rows {
// print("[DEBUG] 原始可加载记录数:${_rows.length}");
return _rows.asMap().entries.map((entry) {
final index = entry.key;
final rowData = entry.value;
return DataGridRow(cells: cells);
}).toList();
return DataGridRow(
cells: [
DataGridCell<int>(columnName: 'index', value: index + 1),
...selectedNodes.map((node) {
return DataGridCell<String>(
columnName: node.path,
value: rowData[node.path]?.toString() ?? '',
);
}).toList(),
],
);
}).toList();
}
@override
DataGridRowAdapter? buildRow(DataGridRow row) {

Loading…
Cancel
Save