Browse Source

Mustache格式化完成

master
hejl 2 months ago
parent
commit
7eae3f0735
  1. BIN
      documents/PB UFT模块迁移方案.docx
  2. 2
      win_text_editor/lib/modules/content_search/widgets/results_view.dart
  3. 76
      win_text_editor/lib/modules/data_format/controllers/data_format_controller.dart
  4. 15
      win_text_editor/lib/modules/data_format/controllers/grid_view_controller.dart
  5. 57
      win_text_editor/lib/modules/data_format/services/mustache_service.dart
  6. 22
      win_text_editor/lib/modules/data_format/widgets/data_format_view.dart
  7. 57
      win_text_editor/lib/modules/data_format/widgets/format_text_panel.dart
  8. 7
      win_text_editor/lib/modules/data_format/widgets/grid_view.dart
  9. 16
      win_text_editor/pubspec.lock
  10. 3
      win_text_editor/pubspec.yaml

BIN
documents/PB UFT模块迁移方案.docx

Binary file not shown.

2
win_text_editor/lib/modules/content_search/widgets/results_view.dart

@ -132,7 +132,7 @@ class ResultsView extends StatelessWidget { @@ -132,7 +132,7 @@ class ResultsView extends StatelessWidget {
headerGridLinesVisibility: GridLinesVisibility.both,
allowSorting: false,
allowFiltering: false,
columnWidthMode: ColumnWidthMode.none,
columnWidthMode: ColumnWidthMode.fill,
isScrollbarAlwaysShown: true,
allowColumnsResizing: true, //
columnResizeMode: ColumnResizeMode.onResizeEnd,

76
win_text_editor/lib/modules/data_format/controllers/data_format_controller.dart

@ -1,8 +1,17 @@ @@ -1,8 +1,17 @@
import 'package:flutter/material.dart';
import 'package:win_text_editor/modules/data_format/services/mustache_service.dart';
import 'package:win_text_editor/shared/base/base_content_controller.dart';
import 'grid_view_controller.dart';
class DataFormatController extends BaseContentController {
final GridViewController gridController;
String _templateText = '';
// 使ValueNotifier来管理结果文本
final ValueNotifier<String> _resultTextNotifier = ValueNotifier('');
// notifier给外部访问
ValueNotifier<String> get resultTextNotifier => _resultTextNotifier;
//-------------------
@ -13,11 +22,71 @@ class DataFormatController extends BaseContentController { @@ -13,11 +22,71 @@ class DataFormatController extends BaseContentController {
//
void _setupCrossControllerCommunication() {}
//---------------------
// Set template text from the editor
void setTemplateText(String text) {
_templateText = text;
}
// Apply the template to grid data
void applyTemplate() {
if (_templateText.isEmpty) {
_resultTextNotifier.value = 'Error: Template is empty';
return;
}
// Validate template syntax
if (!MustacheService.validateTemplate(_templateText)) {
_resultTextNotifier.value = 'Error: Invalid Mustache template syntax';
return;
}
// Get variables from template
final templateVars = MustacheService.getTemplateVariables(_templateText);
if (templateVars.isEmpty) {
_resultTextNotifier.value = 'Error: No variables found in template';
return;
}
//-----------------------------
// Get grid data
final gridData = gridController.csvData;
if (gridData.isEmpty || gridData.length < 2) {
_resultTextNotifier.value = 'Error: No CSV data loaded';
return;
}
final headers = gridData.first;
final dataRows = gridData.sublist(1);
// Check if all template variables exist in headers
final missingVars = templateVars.where((varName) => !headers.contains(varName)).toList();
if (missingVars.isNotEmpty) {
_resultTextNotifier.value = 'Error: Template variables not found in CSV headers: ${missingVars.join(', ')}';
return;
}
// Process each row
final resultBuffer = StringBuffer();
for (final row in dataRows) {
final rowData = <String, dynamic>{};
for (var i = 0; i < headers.length; i++) {
if (i < row.length) {
rowData[headers[i]] = row[i];
} else {
rowData[headers[i]] = '';
}
}
try {
final rendered = MustacheService.applyTemplate(_templateText, rowData);
resultBuffer.writeln(rendered);
} catch (e) {
resultBuffer.writeln('Error processing row: $e');
}
}
_resultTextNotifier.value = resultBuffer.toString();
}
//-------------
@override
void onOpenFile(String filePath) {}
@ -28,6 +97,7 @@ class DataFormatController extends BaseContentController { @@ -28,6 +97,7 @@ class DataFormatController extends BaseContentController {
@override
void dispose() {
_resultTextNotifier.dispose(); // dispose时释放资源
gridController.dispose();
super.dispose();
}

15
win_text_editor/lib/modules/data_format/controllers/grid_view_controller.dart

@ -2,6 +2,21 @@ @@ -2,6 +2,21 @@
import 'package:win_text_editor/shared/base/safe_notifier.dart';
class GridViewController extends SafeNotifier {
List<List<dynamic>> _csvData = [];
List<List<dynamic>> get csvData => _csvData;
void setCsvData(List<List<dynamic>> data) {
_csvData = data;
notifyListeners();
}
@override
void dispose() {
// Clean up any resources
super.dispose();
}
void reset() {
//
safeNotify();

57
win_text_editor/lib/modules/data_format/services/mustache_service.dart

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
// mustache_service.dart
import 'package:mustache_template/mustache_template.dart';
class MustacheService {
// Validate Mustache template syntax
static bool validateTemplate(String template) {
try {
Template(template);
return true;
} catch (e) {
return false;
}
}
// Get variables from template
static Set<String> getTemplateVariables(String template) {
try {
final parsed = Template(template);
// Use the source to parse variables manually
return _parseVariablesFromSource(parsed.source);
} catch (e) {
return {};
}
}
// Apply template to a row of data
static String applyTemplate(String template, Map<String, dynamic> data) {
try {
return Template(template).renderString(data);
} catch (e) {
return 'Error applying template: $e';
}
}
// Helper method to parse variables from template source
static Set<String> _parseVariablesFromSource(String source) {
final variables = <String>{};
final pattern = RegExp(r'{{\s*([^{}\s]+)\s*}}');
final matches = pattern.allMatches(source);
for (final match in matches) {
if (match.groupCount >= 1) {
final variable = match.group(1)!;
// Skip sections and special tags
if (!variable.startsWith('#') &&
!variable.startsWith('/') &&
!variable.startsWith('^') &&
!variable.startsWith('>') &&
!variable.startsWith('!')) {
variables.add(variable);
}
}
}
return variables;
}
}

22
win_text_editor/lib/modules/data_format/widgets/data_format_view.dart

@ -39,23 +39,17 @@ class _DataFormatViewState extends State<DataFormatView> { @@ -39,23 +39,17 @@ class _DataFormatViewState extends State<DataFormatView> {
],
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(children: [const SizedBox(height: 8), Expanded(child: _buildMainContent())]),
),
);
}
Widget _buildMainContent() {
return Consumer<DataFormatController>(
builder: (context, controller, _) {
return const Row(
child: Row(
children: [
// GridView (50%)
Expanded(flex: 1, child: Card(child: DataGridView())),
Expanded(
flex: 1,
child: Card(child: DataGridView(controller: _controller.gridController)),
),
// FormatText (50%)
Expanded(flex: 1, child: FormatTextPanel()),
Expanded(flex: 1, child: FormatTextPanel(controller: _controller)),
],
);
},
),
),
);
}
}

57
win_text_editor/lib/modules/data_format/widgets/format_text_panel.dart

@ -1,9 +1,12 @@ @@ -1,9 +1,12 @@
import 'package:flutter/material.dart';
import 'package:win_text_editor/modules/data_format/controllers/data_format_controller.dart';
import 'package:win_text_editor/shared/components/editor_toolbar.dart';
import 'package:win_text_editor/shared/components/text_editor.dart';
class FormatTextPanel extends StatelessWidget {
const FormatTextPanel({super.key});
final DataFormatController controller;
const FormatTextPanel({super.key, required this.controller});
@override
Widget build(BuildContext context) {
@ -11,38 +14,46 @@ class FormatTextPanel extends StatelessWidget { @@ -11,38 +14,46 @@ class FormatTextPanel extends StatelessWidget {
child: Column(
children: [
// (200px)
const SizedBox(
SizedBox(
height: 200,
child: TextEditor(tabId: 'format_template', title: 'Mustache模板'),
child: TextEditor(
tabId: 'format_template',
title: 'Mustache模板',
onContentChanged: controller.setTemplateText,
),
),
const SizedBox(height: 6),
// ()
Expanded(
child: TextEditor(
tabId: 'format_result',
title: '转换结果',
toolbarBuilder:
(context, state) => EditorToolbar(
title: '转换结果',
text: state.currentText,
isLoading: state.isLoading,
showOpenFileButton: false, //
customButtons: [
ToolbarButtonConfig(
icon: Icons.code,
tooltip: '格式化',
onPressed: () => _applyFormat(state.currentText),
child: ValueListenableBuilder<String>(
valueListenable: controller.resultTextNotifier,
builder: (context, resultText, _) {
return TextEditor(
tabId: 'format_result',
title: '转换结果',
initialContent: resultText,
toolbarBuilder:
(context, state) => EditorToolbar(
title: '转换结果',
text: state.currentText,
isLoading: state.isLoading,
showOpenFileButton: false,
customButtons: [
ToolbarButtonConfig(
icon: Icons.code,
tooltip: '格式化',
onPressed: () => controller.applyTemplate(),
),
],
onCopyToClipboard: state.copyToClipboard,
onSaveFile: state.saveFile,
),
],
onCopyToClipboard: state.copyToClipboard,
onSaveFile: state.saveFile,
),
);
},
),
),
],
),
);
}
void _applyFormat(String currentText) {}
}

7
win_text_editor/lib/modules/data_format/widgets/grid_view.dart

@ -3,9 +3,12 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @@ -3,9 +3,12 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:file_picker/file_picker.dart';
import 'dart:io';
import 'package:csv/csv.dart';
import 'package:win_text_editor/modules/data_format/controllers/grid_view_controller.dart';
class DataGridView extends StatefulWidget {
const DataGridView({super.key});
final GridViewController controller;
const DataGridView({super.key, required this.controller});
@override
State<DataGridView> createState() => _DataGridViewState();
@ -127,6 +130,8 @@ class _DataGridViewState extends State<DataGridView> { @@ -127,6 +130,8 @@ class _DataGridViewState extends State<DataGridView> {
setState(() {
_csvData = dataWithIndex;
});
widget.controller.setCsvData(dataWithIndex);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('加载CSV文件失败: $e')));

16
win_text_editor/pubspec.lock

@ -248,6 +248,14 @@ packages: @@ -248,6 +248,14 @@ packages:
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.16.0"
mustache_template:
dependency: "direct main"
description:
name: mustache_template
sha256: a46e26f91445bfb0b60519be280555b06792460b27b19e2b19ad5b9740df5d1c
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "2.0.0"
nested:
dependency: transitive
description:
@ -401,18 +409,18 @@ packages: @@ -401,18 +409,18 @@ packages:
dependency: transitive
description:
name: syncfusion_flutter_core
sha256: "9f0a4593f7642b2f106e329734d0e5fc746baf8d0a59495eec586cd0d9ba7d02"
sha256: a2427697bfad5b611db78ea4c4daef82d3350b83c729a8dc37959662a31547f9
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "22.2.12"
version: "23.2.7"
syncfusion_flutter_datagrid:
dependency: "direct main"
description:
name: syncfusion_flutter_datagrid
sha256: ae93228333ebed39bc59c90bc40cfd3d5a0361591a330fe551b355d3a49a265c
sha256: "9f621f6344d2ed7ea3a8d0ff5c145c174f1e227d6d8851290591ceb718e44600"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "22.2.12"
version: "23.2.7"
term_glyph:
dependency: transitive
description:

3
win_text_editor/pubspec.yaml

@ -18,10 +18,11 @@ dependencies: @@ -18,10 +18,11 @@ dependencies:
expandable: ^5.0.1
collection: ^1.17.0
path: ^1.8.0
syncfusion_flutter_datagrid: ^22.1.40
syncfusion_flutter_datagrid: ^23.1.40
flutter_js: ^0.8.3
xml: ^6.5.0
csv: ^6.0.0
mustache_template: ^2.0.0
dev_dependencies:
flutter_test:

Loading…
Cancel
Save