Browse Source

界面调整OK

master
hejl 2 months ago
parent
commit
f631654314
  1. 4
      win_text_editor/lib/framework/controllers/tab_items_controller.dart
  2. 14
      win_text_editor/lib/framework/widgets/tab_view.dart
  3. 110
      win_text_editor/lib/modules/data_compare/controllers/data_compare_controller.dart
  4. 93
      win_text_editor/lib/modules/data_compare/widgets/data_compare_grid.dart
  5. 189
      win_text_editor/lib/modules/data_compare/widgets/data_compare_view.dart
  6. 16
      win_text_editor/lib/modules/data_format/widgets/data_format_view.dart
  7. 16
      win_text_editor/lib/modules/demo/widgets/demo_view.dart
  8. 17
      win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart

4
win_text_editor/lib/framework/controllers/tab_items_controller.dart

@ -116,4 +116,8 @@ class TabItemsController with ChangeNotifier { @@ -116,4 +116,8 @@ class TabItemsController with ChangeNotifier {
}
activeContentController?.onOpenFile(filePath);
}
bool hasController(String tabId) {
return _contentControllers.containsKey(tabId);
}
}

14
win_text_editor/lib/framework/widgets/tab_view.dart

@ -55,7 +55,12 @@ class _TabViewState extends State<TabView> { @@ -55,7 +55,12 @@ class _TabViewState extends State<TabView> {
}
Widget _buildTabItem(AppTab tab, ChangeNotifier? controller) {
return ModuleRouter.buildWidgetForTab(tab, controller);
return Container(
decoration: const BoxDecoration(
border: Border(top: BorderSide(color: Colors.lightBlue, width: 1)),
),
child: ModuleRouter.buildWidgetForTab(tab, controller),
);
}
}
@ -78,12 +83,7 @@ class _TabItem extends StatelessWidget { @@ -78,12 +83,7 @@ class _TabItem extends StatelessWidget {
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: isActive ? Colors.blue[100] : Colors.grey[200],
border: Border(
bottom: BorderSide(color: isActive ? Colors.blue : Colors.transparent, width: 2),
),
),
decoration: BoxDecoration(color: isActive ? Colors.blue[100] : Colors.grey[200]),
child: Row(
children: [
if (tab.icon != null) Icon(tab.icon, size: 16),

110
win_text_editor/lib/modules/data_compare/controllers/data_compare_controller.dart

@ -1,6 +1,80 @@ @@ -1,6 +1,80 @@
import 'package:flutter/material.dart';
import 'package:win_text_editor/shared/base/base_content_controller.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
class DataCompareController extends BaseContentController {
List<String> leftColumns = [];
List<String> rightColumns = [];
List<Map<String, dynamic>> leftData = [];
List<Map<String, dynamic>> rightData = [];
late DataCompareDataSource dataSource;
DataCompareController() {
dataSource = DataCompareDataSource(this);
}
void importLeftTable(String csvContent) {
final lines = csvContent.split('\n');
if (lines.isEmpty) return;
// Parse headers (skip first column which is for serial number)
leftColumns = lines[0].split(',').skip(1).toList();
// Parse data
leftData = [];
for (int i = 1; i < lines.length; i++) {
if (lines[i].trim().isEmpty) continue;
final values = lines[i].split(',');
final row = {'serial': i.toString(), 'key': values[0]};
for (int j = 0; j < leftColumns.length; j++) {
row[leftColumns[j]] = j + 1 < values.length ? values[j + 1] : '';
}
leftData.add(row);
}
_compareData();
notifyListeners();
}
void importRightTable(String csvContent) {
final lines = csvContent.split('\n');
if (lines.isEmpty) return;
// Parse headers (skip first column which is for serial number)
rightColumns = lines[0].split(',').skip(1).toList();
// Parse data
rightData = [];
for (int i = 1; i < lines.length; i++) {
if (lines[i].trim().isEmpty) continue;
final values = lines[i].split(',');
final row = {'serial': i.toString(), 'key': values[0]};
for (int j = 0; j < rightColumns.length; j++) {
row[rightColumns[j]] = j + 1 < values.length ? values[j + 1] : '';
}
rightData.add(row);
}
_compareData();
notifyListeners();
}
void _compareData() {
// Implement comparison logic here
// This would update the comparison status for each row
dataSource.updateData(leftData, rightData);
}
void exportLeftTable(String matchType) {
// Implement export logic based on matchType
// 'full_match', 'key_match', or 'no_match'
}
void exportRightTable(String matchType) {
// Implement export logic based on matchType
// 'full_match', 'key_match', or 'no_match'
}
@override
void onOpenFile(String filePath) {
// TODO: implement onOpenFile
@ -11,3 +85,39 @@ class DataCompareController extends BaseContentController { @@ -11,3 +85,39 @@ class DataCompareController extends BaseContentController {
// TODO: implement onOpenFolder
}
}
class DataCompareDataSource extends DataGridSource {
final DataCompareController controller;
List<DataGridRow> _rows = [];
DataCompareDataSource(this.controller) {
_rows = [];
}
void updateData(List<Map<String, dynamic>> leftData, List<Map<String, dynamic>> rightData) {
_rows = [];
// Implement logic to combine left and right data into rows
// and determine comparison status
notifyListeners();
}
@override
List<DataGridRow> get rows => _rows;
@override
DataGridRowAdapter? buildRow(DataGridRow row) {
return DataGridRowAdapter(
cells:
row.getCells().map<Widget>((dataGridCell) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(8),
child:
dataGridCell.value.runtimeType == Icon
? dataGridCell.value
: Text(dataGridCell.value.toString()),
);
}).toList(),
);
}
}

93
win_text_editor/lib/modules/data_compare/widgets/data_compare_grid.dart

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:win_text_editor/modules/data_compare/controllers/data_compare_controller.dart';
class DataCompareGrid extends StatelessWidget {
final DataCompareController controller;
const DataCompareGrid({super.key, required this.controller});
@override
Widget build(BuildContext context) {
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(2.0), //
),
child: SfDataGrid(
source: controller.dataSource,
columns: _buildColumns(),
stackedHeaderRows: _buildStackedHeaders(),
columnWidthMode: ColumnWidthMode.fill,
gridLinesVisibility: GridLinesVisibility.both,
headerGridLinesVisibility: GridLinesVisibility.both,
),
);
}
List<GridColumn> _buildColumns() {
return [
//
GridColumn(columnName: 'left_serial', width: 60, label: _buildHeaderCell('序号')),
GridColumn(columnName: 'left_key', label: _buildHeaderCell('主键')),
...controller.leftColumns.map(
(col) => GridColumn(columnName: 'left_$col', label: _buildHeaderCell(col)),
),
//
GridColumn(
columnName: 'comparison',
label: _buildHeaderCell('对比', color: Colors.purple[50]),
width: 80,
),
//
GridColumn(columnName: 'right_serial', width: 60, label: _buildHeaderCell('序号')),
GridColumn(columnName: 'right_key', label: _buildHeaderCell('主键')),
...controller.rightColumns.map(
(col) => GridColumn(columnName: 'right_$col', label: _buildHeaderCell(col)),
),
];
}
List<StackedHeaderRow> _buildStackedHeaders() {
return [
//
StackedHeaderRow(
cells: [
StackedHeaderCell(
columnNames: [
'left_serial',
'left_key',
...controller.leftColumns.map((col) => 'left_$col'),
],
child: _buildGroupHeader('左表', color: Colors.green[50]),
),
//
// StackedHeaderCell(columnNames: ["comparison"], child: Container()),
StackedHeaderCell(
columnNames: [
'right_serial',
'right_key',
...controller.rightColumns.map((col) => 'right_$col'),
],
child: _buildGroupHeader('右表', color: Colors.blue[50]),
),
],
),
];
}
Container _buildHeaderCell(String text, {Color? color}) {
return Container(
alignment: Alignment.center,
color: color ?? Colors.grey[200],
child: Text(text, style: const TextStyle(fontWeight: FontWeight.bold)),
);
}
Container _buildGroupHeader(String text, {Color? color}) {
return Container(
alignment: Alignment.center,
color: color ?? Colors.purple[50],
child: Text(text, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
);
}
}

189
win_text_editor/lib/modules/data_compare/widgets/data_compare_view.dart

@ -1,7 +1,11 @@ @@ -1,7 +1,11 @@
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:win_text_editor/framework/controllers/tab_items_controller.dart';
import 'package:win_text_editor/modules/data_compare/controllers/data_compare_controller.dart';
import 'data_compare_grid.dart'; //
class DataCompareView extends StatefulWidget {
final String tabId;
@ -13,28 +17,203 @@ class DataCompareView extends StatefulWidget { @@ -13,28 +17,203 @@ class DataCompareView extends StatefulWidget {
class _DataCompareViewState extends State<DataCompareView> {
late final DataCompareController _controller;
late final DataGridController _dataGridController;
bool _isControllerFromTabManager = false;
get tabManager => Provider.of<TabItemsController>(context, listen: false);
@override
void initState() {
super.initState();
_controller = tabManager.getController(widget.tabId) ?? DataCompareController();
_dataGridController = DataGridController();
final controllerFromManager = tabManager.getController(widget.tabId);
if (controllerFromManager != null) {
_controller = controllerFromManager;
_isControllerFromTabManager = true;
} else {
_controller = DataCompareController();
_isControllerFromTabManager = false;
tabManager.registerController(widget.tabId, _controller);
}
}
@override
void dispose() {
_controller.dispose();
_dataGridController.dispose();
if (!_isControllerFromTabManager) {
_controller.dispose();
}
super.dispose();
}
Future<void> _importLeftTable() async {
try {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['csv'],
);
if (result != null) {
final file = result.files.single;
final content = await rootBundle.loadString(file.path!);
_controller.importLeftTable(content);
}
} catch (e) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Failed to import left table: $e')));
}
}
Future<void> _importRightTable() async {
try {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['csv'],
);
if (result != null) {
final file = result.files.single;
final content = await rootBundle.loadString(file.path!);
_controller.importRightTable(content);
}
} catch (e) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Failed to import right table: $e')));
}
}
//
Widget _buildExportButton(bool isLeftTable) {
return ElevatedButton(
onPressed: () {
_showExportMenu(isLeftTable);
},
style: ElevatedButton.styleFrom(
backgroundColor: isLeftTable ? Colors.green[50] : Colors.blue[50],
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: Row(
children: [
const Icon(Icons.output, size: 18),
const SizedBox(width: 4),
Text('导出${isLeftTable ? '左表' : '右表'}'),
],
),
);
}
//
void _showExportMenu(bool isLeftTable) {
final RenderBox button = context.findRenderObject() as RenderBox;
final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
final RelativeRect position = RelativeRect.fromRect(
Rect.fromPoints(
button.localToGlobal(Offset.zero, ancestor: overlay), //
button.localToGlobal(button.size.bottomRight(Offset.zero), ancestor: overlay),
),
Offset.zero & overlay.size,
);
showMenu<String>(
context: context,
position: position,
items: [
const PopupMenuItem(
value: 'full_match',
child: Row(
children: [
Icon(Icons.double_arrow, color: Colors.green),
SizedBox(width: 8),
Text('整行匹配'),
],
),
),
const PopupMenuItem(
value: 'key_match',
child: Row(
children: [
Icon(Icons.arrow_forward_ios, color: Colors.blue),
SizedBox(width: 8),
Text('主键匹配'),
],
),
),
const PopupMenuItem(
value: 'no_match',
child: Row(
children: [Icon(Icons.close, color: Colors.red), SizedBox(width: 8), Text('不匹配')],
),
),
],
).then((value) {
if (value != null) {
if (isLeftTable) {
_controller.exportLeftTable(value);
} else {
_controller.exportRightTable(value);
}
}
});
}
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: _controller,
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Column(children: [Expanded(flex: 1, child: Text("空白"))]),
child: Consumer<DataCompareController>(
builder: (context, controller, child) {
return Padding(
padding: const EdgeInsets.only(left: 4.0, right: 4.0),
child: Column(
children: [
Container(
height: 50,
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
ElevatedButton(
onPressed: _importLeftTable,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green[50],
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: const Text('导入左表(CSV)'),
),
const SizedBox(width: 8),
_buildExportButton(true), // 使
],
),
Row(
children: [
ElevatedButton(
onPressed: _importRightTable,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue[50],
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: const Text('导入右表(CSV)'),
),
const SizedBox(width: 8),
_buildExportButton(false), // 使
],
),
],
),
),
Expanded(child: DataCompareGrid(controller: controller)),
],
),
);
},
),
);
}

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

@ -16,17 +16,29 @@ class DataFormatView extends StatefulWidget { @@ -16,17 +16,29 @@ class DataFormatView extends StatefulWidget {
class _DataFormatViewState extends State<DataFormatView> {
late final DataFormatController _controller;
bool _isControllerFromTabManager = false;
get tabManager => Provider.of<TabItemsController>(context, listen: false);
@override
void initState() {
super.initState();
_controller = tabManager.getController(widget.tabId) ?? DataFormatController();
final controllerFromManager = tabManager.getController(widget.tabId);
if (controllerFromManager != null) {
_controller = controllerFromManager;
_isControllerFromTabManager = true;
} else {
_controller = DataFormatController();
_isControllerFromTabManager = false;
tabManager.registerController(widget.tabId, _controller);
}
}
@override
void dispose() {
_controller.dispose();
if (!_isControllerFromTabManager) {
_controller.dispose();
}
super.dispose();
}

16
win_text_editor/lib/modules/demo/widgets/demo_view.dart

@ -13,18 +13,30 @@ class DemoView extends StatefulWidget { @@ -13,18 +13,30 @@ class DemoView extends StatefulWidget {
class _DemoViewState extends State<DemoView> {
late final DemoController _controller;
bool _isControllerFromTabManager = false;
get tabManager => Provider.of<TabItemsController>(context, listen: false);
@override
void initState() {
super.initState();
_controller = tabManager.getController(widget.tabId) ?? DemoController();
final controllerFromManager = tabManager.getController(widget.tabId);
if (controllerFromManager != null) {
_controller = controllerFromManager;
_isControllerFromTabManager = true;
} else {
_controller = DemoController();
_isControllerFromTabManager = false;
tabManager.registerController(widget.tabId, _controller);
}
}
@override
void dispose() {
_controller.dispose();
if (!_isControllerFromTabManager) {
_controller.dispose();
}
super.dispose();
}

17
win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart

@ -17,17 +17,30 @@ class TemplateParserView extends StatefulWidget { @@ -17,17 +17,30 @@ class TemplateParserView extends StatefulWidget {
class _TemplateParserViewState extends State<TemplateParserView> {
late final TemplateParserController _controller;
bool _isControllerFromTabManager = false;
get tabManager => Provider.of<TabItemsController>(context, listen: false);
@override
void initState() {
super.initState();
_controller = tabManager.getController(widget.tabId) ?? TemplateParserController();
final controllerFromManager = tabManager.getController(widget.tabId);
if (controllerFromManager != null) {
_controller = controllerFromManager;
_isControllerFromTabManager = true;
} else {
_controller = TemplateParserController();
_isControllerFromTabManager = false;
tabManager.registerController(widget.tabId, _controller);
}
}
@override
void dispose() {
_controller.dispose();
if (!_isControllerFromTabManager) {
_controller.dispose();
}
super.dispose();
}

Loading…
Cancel
Save