更新项目配置和重构代码逻辑

- 更新 .gitignore 文件以包含 Visual Studio 自动生成的内容。
- 在 launch.json 中添加 .NET Core 启动和附加配置。
- 在 tasks.json 中添加构建、发布和监视任务的配置。
- 修改 MarkdownWpfRenderer.cs 中表格列的遍历逻辑,使用更安全的列索引变量,并添加列对齐方式处理。
- 修改 Excel2Prompt.cs 中 ConverterToPrompt 方法的参数类型,更新列名处理逻辑。
- 重构 AiMessageControll.xaml.cs 中的发送命令逻辑,提取 InvokeSendCommand 方法以减少重复代码。
- 在 ImportViewModel.cs 中添加列名映射字典,更新 GenColumns 方法以使用该映射字典,改进 Excel 数据处理逻辑。
- 添加对 Excel 数据处理的逻辑,以支持使用列名映射。
- 移除不再需要的 GenColumns 方法的旧实现,并将扩展方法 ReplaceMultiple 移到类外部以提高可重用性。
This commit is contained in:
Ling 2025-03-04 23:42:16 +08:00
commit 6d6935c84d
7 changed files with 214 additions and 79 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
################################################################################
# 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。
################################################################################
/src/.vs

24
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,24 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/src/ExcelHelper/bin/Debug/net9.0-windows/ExcelHelper.dll",
"args": [],
"cwd": "${workspaceFolder}/src/ExcelHelper",
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

41
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/src/ExcelHelper/ExcelHelper.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/src/ExcelHelper/ExcelHelper.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/src/ExcelHelper/ExcelHelper.csproj"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@ -192,7 +192,7 @@ public class MarkdownWpfRenderer
tableElement
.BindTableBackground();
foreach (var col in table.ColumnDefinitions)
foreach (var _ in table.ColumnDefinitions)
{
if (cancellationToken.IsCancellationRequested)
return new FrameworkElement();
@ -200,7 +200,7 @@ public class MarkdownWpfRenderer
tableContentElement.ColumnDefinitions.Add(
new ColumnDefinition()
{
Width = GridLength.Auto
Width = GridLength.Auto,
});
}
@ -219,12 +219,12 @@ public class MarkdownWpfRenderer
Height = GridLength.Auto
});
int colIndex = 0;
var colIndex = 0;
foreach (var colBlock in row)
{
if (colBlock is not TableCell cell)
continue;
var col = table.ColumnDefinitions[colIndex];
Border cellElement = new Border()
{
Padding = new Thickness(NormalSize / 2, NormalSize / 4, NormalSize / 2, NormalSize / 4)
@ -236,7 +236,7 @@ public class MarkdownWpfRenderer
cellElement.Child = cellContentElement;
cellElement
.BindTableBorder();
//block.
cellContentElement.Margin = new Thickness(4);
if (rowIndex % 2 == 1)
@ -244,6 +244,19 @@ public class MarkdownWpfRenderer
Grid.SetRow(cellElement, rowIndex);
Grid.SetColumn(cellElement, colIndex);
if (col.Alignment == TableColumnAlign.Left)
{
cellContentElement.HorizontalAlignment = HorizontalAlignment.Left;
}
else if (col.Alignment == TableColumnAlign.Center)
{
cellContentElement.HorizontalAlignment = HorizontalAlignment.Center;
}
else if (col.Alignment == TableColumnAlign.Right)
{
cellContentElement.HorizontalAlignment = HorizontalAlignment.Right;
}
tableContentElement.Children.Add(cellElement);

View File

@ -14,7 +14,7 @@ public class Excel2Prompt
/// <param name="columns"></param>
/// <param name="startCell">A</param>
/// <returns></returns>
public static string ConverterToPrompt(IEnumerable<dynamic> excelData, IEnumerable<string> columns, string startCell,string sheetName)
public static string ConverterToPrompt(IEnumerable<dynamic> excelData, Dictionary<string, string> columns, string startCell,string sheetName)
{
/*
:
@ -46,13 +46,15 @@ public class Excel2Prompt
int columnIndex = startColumnIndex;
foreach (var column in columns)
{
var colOriName = column.Key;
var safeColName = column.Value;
columnIndex++;
string columnLetter = GetExcelColumnName(columnIndex);
var columnData = dataList.Select(row =>
{
var rowDict = (IDictionary<string, object>)row;
return rowDict.ContainsKey(column) ? rowDict[column] : null;
return rowDict.ContainsKey(safeColName) ? rowDict[safeColName] : null;
}).ToList();
var nonNullData = columnData.Where(value => value != null).ToList();
@ -63,7 +65,7 @@ public class Excel2Prompt
// 自动识别数据类型
var dataType = GetColumnDataType(nonNullData);
var prompt = $"- Column '{column.Replace("\n", " ")}' (Excel Column {columnLetter})" +
var prompt = $"- Column '{column.Key.Replace("\n", " ")}' (Excel Column {columnLetter})" +
$" - Type: {dataType}" +
$" - Sample values: ['{string.Join("', '", sampleValues)}']";
prompts.Add(prompt);

View File

@ -80,24 +80,27 @@ public partial class AiMessageControll : UserControl
private void SendButton_Click(object sender, RoutedEventArgs e)
{
if (SendCommand != null && SendCommand.CanExecute(CurrentMessage))
{
SendCommand.Execute(CurrentMessage);
}
InvokeSendCommand();
}
private void MessageInput_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter && !string.IsNullOrEmpty(CurrentMessage) && !IsWaiting)
{
if (SendCommand != null && SendCommand.CanExecute(CurrentMessage))
{
SendCommand.Execute(CurrentMessage);
}
InvokeSendCommand();
e.Handled = true;
}
}
private void InvokeSendCommand()
{
if (SendCommand != null && SendCommand.CanExecute(CurrentMessage))
{
SendCommand.Execute(CurrentMessage);
CurrentMessage = "";
}
}
public void ScrollToEnd()
{
if (Messages.Count > 0)

View File

@ -15,13 +15,75 @@ using ExcelHelper.Views.Components;
using MiniExcelLibs;
using MiniExcelLibs.OpenXml;
using SqlSugar;
using System.Text.RegularExpressions;
using System.Dynamic;
using System.Diagnostics;
namespace ExcelHelper.Views.ViewModels;
public partial class ImportViewModel : ObservableRecipient, IViewModel
{
// 新增列名映射字典
private readonly Dictionary<string, string> _columnMappings = new();
private void GenColumns(IEnumerable<string> columns)
{
ExcelColumns.Clear();
TableColumns.Clear();
_columnMappings.Clear();
if (UseHeaderRow)
{
foreach (var columnName in columns)
{
// 修改正则表达式,保留中文字符(\u4e00-\u9fff
var safeColumnName = Regex.Replace(columnName, @"[^a-zA-Z0-9\u4e00-\u9fff]", "_")
.Trim('_')
.ReplaceMultiple("__", "_");
_columnMappings[columnName] = safeColumnName; // 保存映射关系
var column = new DataGridTextColumn
{
Header = columnName,
Binding = new System.Windows.Data.Binding($"{safeColumnName}"), // 恢复方括号语法
Width = DataGridLength.Auto
};
ExcelColumns.Add(column);
}
}
else
{
for (var i = 'A'; i < 'Z'; i++)
{
var column = new DataGridTextColumn
{
Header = $"{i}",
Binding = new System.Windows.Data.Binding($"{i}"),
Width = DataGridLength.Auto
};
ExcelColumns.Add(column);
}
}
var columnsSeq = 0;
foreach (var item in ExcelColumns)
{
TableColumns.Add(new TableColumnModel
{
ExcelColumnName = item.Header.ToString(),
TableColumnName = $"Column{columnsSeq}",
});
columnsSeq++;
}
if (ExcelColumns.Count > 0)
{
WeakReferenceMessenger.Default.Send(new UpdateDataGridColumnsMessage([.. ExcelColumns]));
}
else
{
WeakReferenceMessenger.Default.Send(new ErrorDialogMessage("未读取到列信息!"));
}
}
private readonly AiHelper AiHelper = new("deepseek-r1-250120", false);
public Task FileDrop(string[] files)
@ -67,15 +129,7 @@ public partial class ImportViewModel : ObservableRecipient, IViewModel
IsLoading = false;
return;
}
var excelData = await GetExcelData(path, config);
if (MaxRow != 0)
{
ExcelData = excelData.Take(Math.Min(MaxRow, 300));
}
else
{
ExcelData = excelData.Take(300);
}
var currentSheetName = SelectedSheetName;
var columns = MiniExcel.GetColumns(path, useHeaderRow: UseHeaderRow, startCell: StartCell, sheetName: currentSheetName, configuration: config);
@ -90,9 +144,42 @@ public partial class ImportViewModel : ObservableRecipient, IViewModel
{
SelectedSheetName = Sheets.FirstOrDefault(it => it.Equals(currentSheetName));
}
var excelData = await GetExcelData(path, config);
// 新增数据处理逻辑
if (UseHeaderRow)
{
var processedData = new List<ExpandoObject>();
foreach (var row in excelData)
{
var newRow = new ExpandoObject();
var newRowDict = (IDictionary<string, object>)newRow;
var originalRow = (IDictionary<string, object>)row;
foreach (var col in columns)
{
if (_columnMappings.TryGetValue(col, out var safeName)
&& originalRow.TryGetValue(col, out var value))
{
newRowDict[safeName] = value;
Debug.WriteLine($"Mapping {col} to {safeName}");
}
}
processedData.Add(newRow);
}
excelData = processedData;
}
if (MaxRow != 0)
{
ExcelData = excelData.Take(Math.Min(MaxRow, 300));
}
else
{
ExcelData = excelData.Take(300);
}
MaxRow = ExcelData.Count();
ExcelPromptString = Excel2Prompt.ConverterToPrompt(excelData, columns,StartCell,currentSheetName);
ExcelPromptString = Excel2Prompt.ConverterToPrompt(excelData, _columnMappings, StartCell,currentSheetName);
}
catch (Exception ex)
{
@ -108,57 +195,6 @@ public partial class ImportViewModel : ObservableRecipient, IViewModel
: MiniExcel.QueryRange(path, sheetName: SelectedSheetName, useHeaderRow: UseHeaderRow, startCell: StartCell, endCell: EndCell, configuration: config);
}
private void GenColumns(IEnumerable<string> columns)
{
ExcelColumns.Clear();
TableColumns.Clear();
if (UseHeaderRow)
{
foreach (var columnName in columns)
{
var column = new DataGridTextColumn
{
Header = columnName,
Binding = new System.Windows.Data.Binding($"{columnName}"),
Width = DataGridLength.Auto
};
ExcelColumns.Add(column);
}
}
else
{
for (var i = 'A'; i < 'Z'; i++)
{
var column = new DataGridTextColumn
{
Header = $"{i}",
Binding = new System.Windows.Data.Binding($"{i}"),
Width = DataGridLength.Auto
};
ExcelColumns.Add(column);
}
}
var columnsSeq = 0;
foreach (var item in ExcelColumns)
{
TableColumns.Add(new TableColumnModel
{
ExcelColumnName = item.Header.ToString(),
TableColumnName = $"Column{columnsSeq}",
});
columnsSeq++;
}
if (ExcelColumns.Count > 0)
{
WeakReferenceMessenger.Default.Send(new UpdateDataGridColumnsMessage([.. ExcelColumns]));
}
else
{
WeakReferenceMessenger.Default.Send(new ErrorDialogMessage("未读取到列信息!"));
}
}
[RelayCommand]
private void OnReLoadExcel()
{
@ -437,3 +473,14 @@ public partial class ImportViewModel : ObservableRecipient, IViewModel
private string _excelPromptString;
#endregion
}
// 将扩展方法移到类外部
public static class StringExtensions
{
public static string ReplaceMultiple(this string input, string oldValue, string newValue)
{
while (input.Contains(oldValue))
input = input.Replace(oldValue, newValue);
return input;
}
}