Browse Source

组件列表展示OK

master
hejl 2 months ago
parent
commit
086f9ae021
  1. 68
      win_text_editor/lib/modules/memory_table/services/memory_table_service.dart
  2. 51
      win_text_editor/lib/modules/uft_component/controllers/component_source.dart
  3. 57
      win_text_editor/lib/modules/uft_component/controllers/uft_component_controller.dart
  4. 28
      win_text_editor/lib/modules/uft_component/models/uft_component.dart
  5. 78
      win_text_editor/lib/modules/uft_component/services/uft_component_service.dart
  6. 106
      win_text_editor/lib/modules/uft_component/widgets/component_grid.dart
  7. 43
      win_text_editor/lib/modules/uft_component/widgets/uft_component_left_side.dart
  8. 18
      win_text_editor/lib/shared/uft_std_fields/field_data_service.dart

68
win_text_editor/lib/modules/memory_table/services/memory_table_service.dart

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:win_text_editor/modules/memory_table/models/memory_table.dart'; import 'package:win_text_editor/modules/memory_table/models/memory_table.dart';
import 'package:win_text_editor/shared/data/std_fields_cache.dart'; import 'package:win_text_editor/shared/data/std_fields_cache.dart';
import 'package:win_text_editor/shared/models/std_filed.dart'; import 'package:win_text_editor/shared/models/std_filed.dart';
import 'package:win_text_editor/shared/uft_std_fields/field_data_service.dart';
import 'package:xml/xml.dart' as xml; import 'package:xml/xml.dart' as xml;
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:win_text_editor/framework/controllers/logger.dart'; import 'package:win_text_editor/framework/controllers/logger.dart';
@ -23,9 +24,9 @@ class MemoryTableService {
// 2. metadata stdfield.stfield // 2. metadata stdfield.stfield
if (await StdFieldsCache.getLength() == 0) { if (await StdFieldsCache.getLength() == 0) {
_logger.info("加载标准字段缓存"); _logger.info("加载标准字段缓存");
final metadataFile = await _findMetadataFile(filePath); final metadataFile = await FieldDataService.findMetadataFile(filePath);
if (metadataFile != null) { if (metadataFile != null) {
await _processStdFieldFile(metadataFile); await FieldDataService.processStdFieldFile(metadataFile);
} }
} }
@ -97,8 +98,8 @@ class MemoryTableService {
tableName: fileNameWithoutExt, tableName: fileNameWithoutExt,
chineseName: chineseName, chineseName: chineseName,
objectId: objectId, objectId: objectId,
fields: fields.isNotEmpty ? fields : _getDefaultFields(), fields: fields.isNotEmpty ? fields : FieldDataService.getDefaultFields(),
indexes: indexList.isNotEmpty ? indexList : _getDefaultIndexes(), indexes: indexList.isNotEmpty ? indexList : FieldDataService.getDefaultIndexes(),
); );
} on xml.XmlParserException catch (e) { } on xml.XmlParserException catch (e) {
_logger.error("XML解析错误: ${e.message}"); _logger.error("XML解析错误: ${e.message}");
@ -108,65 +109,6 @@ class MemoryTableService {
rethrow; rethrow;
} }
} }
// metadata stdfield.stfield
Future<File?> _findMetadataFile(String filePath) async {
Directory currentDir = File(filePath).parent;
const targetDirName = 'metadata';
const targetFileName = 'stdfield.stdfield';
// metadata
while (true) {
final metadataDir = Directory('${currentDir.path}/$targetDirName');
if (await metadataDir.exists()) {
final stdFieldFile = File('${metadataDir.path}/$targetFileName');
if (await stdFieldFile.exists()) {
return stdFieldFile;
} else {
_logger.error("没找到标准字段文件 $targetFileName");
return null;
}
}
//
if (currentDir.path == currentDir.parent.path) {
_logger.error("没有找到元数据目录 $targetDirName");
return null;
}
currentDir = currentDir.parent;
}
}
//
Future<void> _processStdFieldFile(File stdFieldFile) async {
try {
final content = await stdFieldFile.readAsString();
final document = xml.XmlDocument.parse(content);
final items = document.findAllElements('items');
for (final item in items) {
final name = item.getAttribute('name') ?? '';
final chineseName = item.getAttribute('chineseName') ?? '';
final dataType = item.getAttribute('dataType') ?? '';
if (name.isNotEmpty) {
final stdField = StdField(name: name, chineseName: chineseName, dateType: dataType);
await StdFieldsCache.setData(name, stdField);
}
}
} catch (e) {
_logger.error("处理标准字段文件时出错: $e");
}
}
List<Field> _getDefaultFields() {
return [Field('1', '', '', ''), Field('2', '', '', ''), Field('3', '', '', '')];
}
List<Index> _getDefaultIndexes() {
return [Index('', false, '', ''), Index('', false, '', '')];
}
} }
class TableData { class TableData {

51
win_text_editor/lib/modules/uft_component/controllers/component_source.dart

@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:win_text_editor/modules/uft_component/models/uft_component.dart';
import 'package:win_text_editor/shared/base/base_data_source.dart';
class ComponentSource extends SelectableDataSource<UftComponent> {
ComponentSource(
List<UftComponent> uftComponents, {
required Null Function(dynamic index, dynamic isSelected) onSelectionChanged,
}) : super(uftComponents, onSelectionChanged: onSelectionChanged);
@override
List<DataGridRow> get rows =>
items
.map(
(component) => DataGridRow(
cells: [
DataGridCell<bool>(columnName: 'select', value: component.isSelected),
DataGridCell<int>(columnName: 'id', value: component.id),
DataGridCell<String>(columnName: 'name', value: component.name),
DataGridCell<String>(columnName: 'chineseName', value: component.chineseName),
],
),
)
.toList();
get data => items;
@override
DataGridRowAdapter buildRow(DataGridRow row) {
final rowIndex = effectiveRows.indexOf(row);
return DataGridRowAdapter(
cells:
row.getCells().map<Widget>((cell) {
if (cell.columnName == 'select') {
return Center(
child: Checkbox(
value: items[rowIndex].isSelected,
onChanged: (value) => toggleRowSelection(rowIndex, value),
),
);
}
return Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(cell.value.toString(), overflow: TextOverflow.ellipsis),
);
}).toList(),
);
}
}

57
win_text_editor/lib/modules/uft_component/controllers/uft_component_controller.dart

@ -1,30 +1,41 @@
import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:win_text_editor/framework/controllers/logger.dart'; import 'package:win_text_editor/framework/controllers/logger.dart';
import 'package:win_text_editor/framework/services/macro_template_service.dart'; import 'package:win_text_editor/framework/services/macro_template_service.dart';
import 'package:win_text_editor/modules/uft_component/controllers/component_source.dart';
import 'package:win_text_editor/modules/uft_component/models/uft_component.dart';
import 'package:win_text_editor/modules/uft_component/services/uft_component_service.dart';
import 'package:win_text_editor/shared/models/std_filed.dart'; import 'package:win_text_editor/shared/models/std_filed.dart';
import 'package:win_text_editor/shared/uft_std_fields/field_data_source.dart'; import 'package:win_text_editor/shared/uft_std_fields/field_data_source.dart';
import 'package:win_text_editor/modules/memory_table/models/memory_table.dart'; import 'package:win_text_editor/modules/memory_table/models/memory_table.dart';
import 'package:win_text_editor/modules/memory_table/services/memory_table_service.dart';
import 'package:win_text_editor/shared/base/base_content_controller.dart'; import 'package:win_text_editor/shared/base/base_content_controller.dart';
class UftComponentController extends BaseContentController { class UftComponentController extends BaseContentController {
String? _errorMessage; String? _errorMessage;
String tableName = ""; String componentName = "";
String objectId = "";
String chineseName = ""; String chineseName = "";
late DataGridSource fieldsSource; late DataGridSource fieldsSource;
final MemoryTableService _service; late DataGridSource componentsSource;
final UftComponentService _service;
final MacroTemplateService templateService = MacroTemplateService(); final MacroTemplateService templateService = MacroTemplateService();
// MemoryTable对 //
late MemoryTable _memoryTable; late UftComponent _currentUftComponent;
UftComponentController() : _service = MemoryTableService(Logger()) { UftComponentController() : _service = UftComponentService(Logger()) {
// //
final initialFields = [Field('1', '', '', '', false), Field('2', '', '', '', false)]; final initialFields = [Field('1', '', '', '', false), Field('2', '', '', '', false)];
final initialIndexes = [Index('', false, '', '', false)]; final initalComponents = [
UftComponent(id: 1, name: '', chineseName: '', fields: initialFields),
];
componentsSource = ComponentSource(
initalComponents,
onSelectionChanged: (index, isSelected) {
updateComponentSelection(index, isSelected);
},
);
fieldsSource = FieldsDataSource( fieldsSource = FieldsDataSource(
initialFields, initialFields,
@ -33,14 +44,14 @@ class UftComponentController extends BaseContentController {
}, },
); );
// MemoryTable // uftComponent
_memoryTable = MemoryTable(tableName: '', columns: initialFields, indexes: initialIndexes); _currentUftComponent = UftComponent(id: 0, name: '', chineseName: '', fields: initialFields);
} }
String? get errorMessage => _errorMessage; String? get errorMessage => _errorMessage;
// MemoryTable // UftComponent
MemoryTable get memoryTable => _memoryTable; UftComponent get currentUftComponent => _currentUftComponent;
void initTemplateService() { void initTemplateService() {
if (!templateService.inited) { if (!templateService.inited) {
@ -50,29 +61,17 @@ class UftComponentController extends BaseContentController {
String? genCodeString(List<String> macroList) { String? genCodeString(List<String> macroList) {
initTemplateService(); initTemplateService();
return templateService.renderTemplate(macroList, _memoryTable.toMap()); return templateService.renderTemplate(macroList, _currentUftComponent.toMap());
} }
@override @override
Future<void> onOpenFile(String filePath) async { Future<void> onOpenFile(String filePath) async {
Logger().info("Opening file: $filePath"); Logger().info("Opening file: $filePath");
try { try {
final tableData = await _service.parseStructureFile(filePath); final components = await _service.parseComponentFile(filePath);
// Update controller state
tableName = tableData.tableName;
chineseName = tableData.chineseName;
objectId = tableData.objectId;
// Update data sources // Update data sources
(fieldsSource as FieldsDataSource).updateData(tableData.fields); (componentsSource as ComponentSource).updateData(components);
// MemoryTable对象
_memoryTable = MemoryTable(
tableName: tableName,
columns: tableData.fields,
indexes: tableData.indexes,
);
// Clear any previous error // Clear any previous error
_errorMessage = null; _errorMessage = null;
@ -94,7 +93,7 @@ class UftComponentController extends BaseContentController {
fieldsSource.notifyListeners(); fieldsSource.notifyListeners();
// MemoryTable // MemoryTable
_memoryTable.columns[index].isSelected = isSelected; _currentUftComponent.fields[index].isSelected = isSelected;
notifyListeners(); notifyListeners();
} }
} }
@ -110,4 +109,6 @@ class UftComponentController extends BaseContentController {
void dispose() { void dispose() {
super.dispose(); super.dispose();
} }
void updateComponentSelection(index, isSelected) {}
} }

28
win_text_editor/lib/modules/uft_component/models/uft_component.dart

@ -1,25 +1,37 @@
import 'package:win_text_editor/shared/models/std_filed.dart'; import 'package:win_text_editor/shared/models/std_filed.dart';
class UftComponent { class UftComponent implements SelectableItem {
final String componentName; final int id;
final List<Field> columns; final String name;
final String chineseName;
final List<Field> fields;
@override
bool isSelected;
UftComponent({required this.componentName, required this.columns}); UftComponent({
required this.id,
required this.name,
required this.chineseName,
required this.fields,
this.isSelected = false,
});
List<Field> get selectFields => columns.where((field) => field.isSelected).toList(); List<Field> get selectFields => fields.where((field) => field.isSelected).toList();
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return { return {
'componentName': componentName, 'id': id,
'name': name,
'chineseName': chineseName,
'fields': 'fields':
columns fields
.map( .map(
(field) => { (field) => {
'id': field.id, 'id': field.id,
'name': field.name, 'name': field.name,
'chineseName': field.chineseName, 'chineseName': field.chineseName,
'type': field.type, 'type': field.type,
'isLast': columns.indexOf(field) == columns.length - 1, 'isLast': fields.indexOf(field) == fields.length - 1,
}, },
) )
.toList(), .toList(),

78
win_text_editor/lib/modules/uft_component/services/uft_component_service.dart

@ -1,19 +1,85 @@
// memory_table_service.dart // memory_table_service.dart
import 'dart:io';
import 'package:win_text_editor/modules/uft_component/models/uft_component.dart';
import 'package:win_text_editor/shared/data/std_fields_cache.dart';
import 'package:win_text_editor/shared/models/std_filed.dart'; import 'package:win_text_editor/shared/models/std_filed.dart';
import 'package:win_text_editor/framework/controllers/logger.dart'; import 'package:win_text_editor/framework/controllers/logger.dart';
import 'package:win_text_editor/shared/uft_std_fields/field_data_service.dart';
import 'package:xml/xml.dart' as xml;
class UftComponentService { class UftComponentService {
final Logger _logger; final Logger _logger;
UftComponentService(this._logger); UftComponentService(this._logger);
}
class ComponentData { Future<List<UftComponent>> parseComponentFile(String filePath) async {
final String name; try {
final String chineseName; // 1. Check file extension
final List<Field> fields; if (!filePath.toLowerCase().endsWith('component.xml')) {
throw const FormatException("文件名必须是component.xml");
}
// 2. metadata stdfield.stfield
if (await StdFieldsCache.getLength() == 0) {
_logger.info("加载标准字段缓存");
final metadataFile = await FieldDataService.findMetadataFile(filePath);
if (metadataFile != null) {
await FieldDataService.processStdFieldFile(metadataFile);
}
}
// 3. Read and parse structure file content
final file = File(filePath);
final content = await file.readAsString();
final document = xml.XmlDocument.parse(content);
final componentNodes = document.findAllElements('items');
if (componentNodes.isEmpty) {
throw const FormatException("文件格式错误:缺少items节点");
}
// 4.
final components = <UftComponent>[];
int id = 0;
for (var node in componentNodes) {
if (node.findElements("items").isEmpty) continue;
id++;
final name = node.getAttribute('name') ?? '';
final chineseName = node.getAttribute('chineseName') ?? '';
// 5. Process properties (fields)
final childNodes = node.children;
final fields = <Field>[];
int index = 1;
for (final childNode in childNodes) {
final name = childNode.getAttribute('name') ?? '';
//
final stdField = StdFieldsCache.getData(name);
fields.add(
Field(
(index++).toString(), //
name, //
stdField?.chineseName ?? '', //
stdField?.dateType ?? '', //
),
);
}
components.add(UftComponent(id: id, name: name, chineseName: chineseName, fields: fields));
}
ComponentData({required this.name, required this.chineseName, required this.fields}); return components;
} on xml.XmlParserException catch (e) {
_logger.error("XML解析错误: ${e.message}");
rethrow;
} catch (e) {
_logger.error("处理文件时发生错误: $e");
rethrow;
}
}
} }

106
win_text_editor/lib/modules/uft_component/widgets/component_grid.dart

@ -0,0 +1,106 @@
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:win_text_editor/modules/uft_component/controllers/component_source.dart';
import 'package:win_text_editor/shared/base/base_data_source.dart';
import 'package:win_text_editor/shared/models/std_filed.dart';
class ComponentGrid extends StatelessWidget {
final ComponentSource componentsSource;
final Function(int index, bool isSelected)? onSelectionChanged;
const ComponentGrid({super.key, required this.componentsSource, this.onSelectionChanged});
Container _buildGridHeader(String text) {
return Container(
alignment: Alignment.center,
color: Colors.grey[200],
child: Text(text, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
);
}
Widget _buildCheckboxHeader<T extends SelectableItem>(
BuildContext context,
SelectableDataSource<T> dataSource,
) {
final allSelected =
dataSource.items.isNotEmpty && dataSource.items.every((item) => item.isSelected);
final someSelected =
dataSource.items.isNotEmpty &&
dataSource.items.any((item) => item.isSelected) &&
!allSelected;
return Container(
alignment: Alignment.center,
color: Colors.grey[200],
child: Checkbox(
value: allSelected,
tristate: someSelected,
onChanged: (value) => dataSource.toggleAllSelection(value ?? false),
),
);
}
@override
Widget build(BuildContext context) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
return SizedBox(
width: constraints.maxWidth,
child: SfDataGrid(
source: componentsSource,
gridLinesVisibility: GridLinesVisibility.both,
headerGridLinesVisibility: GridLinesVisibility.both,
columnWidthMode: ColumnWidthMode.fitByCellValue,
selectionMode: SelectionMode.none,
columns: [
GridColumn(
columnName: 'select',
label: ValueListenableBuilder<bool>(
valueListenable: componentsSource.selectionNotifier,
builder:
(context, _, __) => _buildCheckboxHeader(context, componentsSource),
),
width: 60,
),
GridColumn(columnName: 'id', label: _buildGridHeader('序号'), minimumWidth: 80),
GridColumn(
columnName: 'name',
label: _buildGridHeader('名称'),
minimumWidth: 120,
),
GridColumn(
columnName: 'chineseName',
label: _buildGridHeader('中文名'),
minimumWidth: 120,
),
],
onCellTap: (details) {
if (details.column.columnName == 'select') {
final rowIndex = details.rowColumnIndex.rowIndex - 1;
if (rowIndex >= 0 && rowIndex < componentsSource.items.length) {
componentsSource.toggleRowSelection(
rowIndex,
!componentsSource.items[rowIndex].isSelected,
);
onSelectionChanged?.call(
rowIndex,
componentsSource.items[rowIndex].isSelected,
);
}
}
},
),
);
},
),
),
],
),
);
}
}

43
win_text_editor/lib/modules/uft_component/widgets/uft_component_left_side.dart

@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:win_text_editor/modules/uft_component/controllers/component_source.dart';
import 'package:win_text_editor/modules/uft_component/controllers/uft_component_controller.dart'; import 'package:win_text_editor/modules/uft_component/controllers/uft_component_controller.dart';
import 'package:win_text_editor/modules/uft_component/widgets/component_grid.dart';
import 'package:win_text_editor/shared/uft_std_fields/field_data_source.dart'; import 'package:win_text_editor/shared/uft_std_fields/field_data_source.dart';
import 'package:win_text_editor/shared/uft_std_fields/fields_data_grid.dart'; import 'package:win_text_editor/shared/uft_std_fields/fields_data_grid.dart';
@ -13,7 +15,7 @@ class UftComponentLeftSide extends StatelessWidget {
children: [ children: [
Text('$label:'), Text('$label:'),
SizedBox( SizedBox(
width: 200, width: 150,
child: TextField( child: TextField(
controller: TextEditingController(text: value), controller: TextEditingController(text: value),
readOnly: true, readOnly: true,
@ -29,30 +31,25 @@ class UftComponentLeftSide extends StatelessWidget {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(
width: double.infinity,
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Wrap(
spacing: 16,
runSpacing: 8,
children: [
_buildTextFieldRow('名称', controller.tableName),
_buildTextFieldRow('中文名', controller.chineseName),
_buildTextFieldRow('对象编号', controller.objectId),
],
),
),
),
),
const SizedBox(height: 8), const SizedBox(height: 8),
const Padding( Row(
padding: EdgeInsets.all(8.0), children: [
child: Text('字段列表', style: TextStyle(fontWeight: FontWeight.bold)), const SizedBox(width: 8),
_buildTextFieldRow('名称', controller.componentName),
_buildTextFieldRow('中文名', controller.chineseName),
],
), ),
Expanded( Expanded(
flex: 6, flex: 6,
child: ComponentGrid(
componentsSource: controller.componentsSource as ComponentSource,
onSelectionChanged: (index, isSelected) {
controller.updateFieldSelection(index, isSelected);
},
),
),
Expanded(
flex: 3,
child: FieldsDataGrid( child: FieldsDataGrid(
fieldsSource: controller.fieldsSource as FieldsDataSource, fieldsSource: controller.fieldsSource as FieldsDataSource,
onSelectionChanged: (index, isSelected) { onSelectionChanged: (index, isSelected) {
@ -60,10 +57,6 @@ class UftComponentLeftSide extends StatelessWidget {
}, },
), ),
), ),
const Padding(
padding: EdgeInsets.all(8.0),
child: Text('索引列表', style: TextStyle(fontWeight: FontWeight.bold)),
),
], ],
); );
} }

18
win_text_editor/lib/shared/uft_std_fields/field_data_service.dart

@ -7,11 +7,7 @@ import 'package:win_text_editor/shared/models/std_filed.dart';
import 'package:xml/xml.dart' as xml; import 'package:xml/xml.dart' as xml;
class FieldDataService { class FieldDataService {
final Logger _logger; static Future<File?> findMetadataFile(String filePath) async {
FieldDataService(this._logger);
Future<File?> findMetadataFile(String filePath) async {
Directory currentDir = File(filePath).parent; Directory currentDir = File(filePath).parent;
const targetDirName = 'metadata'; const targetDirName = 'metadata';
const targetFileName = 'stdfield.stdfield'; const targetFileName = 'stdfield.stdfield';
@ -24,14 +20,14 @@ class FieldDataService {
if (await stdFieldFile.exists()) { if (await stdFieldFile.exists()) {
return stdFieldFile; return stdFieldFile;
} else { } else {
_logger.error("没找到标准字段文件 $targetFileName"); Logger().error("没找到标准字段文件 $targetFileName");
return null; return null;
} }
} }
// //
if (currentDir.path == currentDir.parent.path) { if (currentDir.path == currentDir.parent.path) {
_logger.error("没有找到元数据目录 $targetDirName"); Logger().error("没有找到元数据目录 $targetDirName");
return null; return null;
} }
@ -40,7 +36,7 @@ class FieldDataService {
} }
// //
Future<void> processStdFieldFile(File stdFieldFile) async { static Future<void> processStdFieldFile(File stdFieldFile) async {
try { try {
final content = await stdFieldFile.readAsString(); final content = await stdFieldFile.readAsString();
final document = xml.XmlDocument.parse(content); final document = xml.XmlDocument.parse(content);
@ -57,15 +53,15 @@ class FieldDataService {
} }
} }
} catch (e) { } catch (e) {
_logger.error("处理标准字段文件时出错: $e"); Logger().error("处理标准字段文件时出错: $e");
} }
} }
List<Field> getDefaultFields() { static List<Field> getDefaultFields() {
return [Field('1', '', '', ''), Field('2', '', '', ''), Field('3', '', '', '')]; return [Field('1', '', '', ''), Field('2', '', '', ''), Field('3', '', '', '')];
} }
List<Index> getDefaultIndexes() { static List<Index> getDefaultIndexes() {
return [Index('', false, '', ''), Index('', false, '', '')]; return [Index('', false, '', ''), Index('', false, '', '')];
} }
} }

Loading…
Cancel
Save