using System.Collections.ObjectModel;
using System.Text;
using System.Text.Json;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NewLife.Studio.Core.DTOs;
namespace NewLife.Studio.Modules.DataStudio.ViewModels;
/// <summary>结果网格 ViewModel</summary>
public partial class ResultGridViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<ColumnInfo> _columns = [];
[ObservableProperty]
private ObservableCollection<object?[]> _rows = [];
[ObservableProperty]
private long _elapsedMs;
[ObservableProperty]
private int _rowCount;
[ObservableProperty]
private bool _isTruncated;
[ObservableProperty]
private string? _error;
public string TruncatedWarning => IsTruncated ? "(结果已裁剪)" : "";
public string ElapsedText => $"耗时: {ElapsedMs}ms";
public string RowCountText => $"行数: {RowCount}";
public bool HasError => !string.IsNullOrEmpty(Error);
public bool HasRows => Rows.Count > 0 && Columns.Count > 0;
public void SetResult(QueryResult result)
{
Columns = new ObservableCollection<ColumnInfo>(result.Columns);
Rows = new ObservableCollection<object?[]>(result.Rows);
ElapsedMs = result.ElapsedMs;
RowCount = result.RowCount;
IsTruncated = result.Truncated;
Error = result.Error;
OnPropertyChanged(nameof(TruncatedWarning));
OnPropertyChanged(nameof(ElapsedText));
OnPropertyChanged(nameof(RowCountText));
OnPropertyChanged(nameof(HasError));
OnPropertyChanged(nameof(HasRows));
}
public async Task ExportCsvAsync(string filePath)
{
var sb = new StringBuilder();
// 写入 UTF-8 BOM 表头
var columnNames = Columns.Select(c => EscapeCsvField(c.Name)).ToList();
sb.AppendLine(string.Join(",", columnNames));
// 写入数据行
foreach (var row in Rows)
{
var fields = new List<string>();
for (int i = 0; i < Columns.Count; i++)
{
var val = i < row.Length ? row[i]?.ToString() ?? "" : "";
fields.Add(EscapeCsvField(val));
}
sb.AppendLine(string.Join(",", fields));
}
await File.WriteAllTextAsync(filePath, sb.ToString(), Encoding.UTF8);
}
public async Task ExportJsonAsync(string filePath)
{
var list = new List<Dictionary<string, object?>>();
foreach (var row in Rows)
{
var dict = new Dictionary<string, object?>();
for (int i = 0; i < Columns.Count; i++)
{
var val = i < row.Length ? row[i] : null;
dict[Columns[i].Name] = val;
}
list.Add(dict);
}
var json = JsonSerializer.Serialize(list, new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
await File.WriteAllTextAsync(filePath, json, Encoding.UTF8);
}
private static string EscapeCsvField(string field)
{
if (field.Contains(',') || field.Contains('"') || field.Contains('\n') || field.Contains('\r'))
{
return $"\"{field.Replace("\"", "\"\"")}\"";
}
return field;
}
}
|