Добавьте файлы проекта.

This commit is contained in:
FrigaT
2026-01-05 00:29:19 +03:00
committed by FrigaT
parent 76a09d80d4
commit d0653c2098
105 changed files with 6729 additions and 0 deletions

View File

@@ -0,0 +1,528 @@
using SQLVision.Core.Enums;
using SQLVision.Core.Interfaces;
using SQLVision.Core.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
namespace SQLVision.UI.ViewModels;
public class MainViewModel : ObservableObject
{
private readonly IScriptManager _scriptManager;
private readonly ISqlExecutionService _executionService;
private readonly IExportService _exportService;
private readonly IControlFactory _controlFactory;
private readonly IVisualizerFactory _visualizerFactory;
private readonly ILogger<MainViewModel> _logger;
private readonly ObservableCollection<ScriptMetadata> _scripts = new();
private readonly ObservableCollection<ScriptCategory> _scriptCategories = new();
private readonly ObservableCollection<ExecutionHistoryItem> _history = new();
private readonly ObservableCollection<ResultTabViewModel> _resultTabs = new();
private ScriptMetadata _selectedScript;
private bool _isBusy;
private string _statusMessage;
private ResultTabViewModel _selectedResultTab;
private string _searchText;
public ObservableCollection<ScriptCategory> ScriptCategories => _scriptCategories;
public ObservableCollection<ExecutionHistoryItem> History => _history;
public ObservableCollection<ResultTabViewModel> ResultTabs => _resultTabs;
public ScriptMetadata SelectedScript
{
get => _selectedScript;
set
{
if (SetProperty(ref _selectedScript, value))
{
OnSelectedScriptChanged();
}
}
}
public bool IsBusy
{
get => _isBusy;
set => SetProperty(ref _isBusy, value);
}
public string StatusMessage
{
get => _statusMessage;
set => SetProperty(ref _statusMessage, value);
}
public ResultTabViewModel SelectedResultTab
{
get => _selectedResultTab;
set => SetProperty(ref _selectedResultTab, value);
}
public string SearchText
{
get => _searchText;
set
{
if (SetProperty(ref _searchText, value))
{
FilterScripts();
}
}
}
public ObservableCollection<ParameterViewModel> Parameters { get; } = new();
public IAsyncRelayCommand LoadScriptsCommand { get; }
public IAsyncRelayCommand ExecuteCommand { get; }
public IAsyncRelayCommand ExportCommand { get; }
public IRelayCommand CopySqlCommand { get; }
public IRelayCommand ClearResultsCommand { get; }
public IRelayCommand SaveParametersCommand { get; }
public IRelayCommand LoadParametersCommand { get; }
public MainViewModel(
IScriptManager scriptManager,
ISqlExecutionService executionService,
IExportService exportService,
IControlFactory controlFactory,
IVisualizerFactory visualizerFactory,
ILogger<MainViewModel> logger)
{
_scriptManager = scriptManager;
_executionService = executionService;
_exportService = exportService;
_controlFactory = controlFactory;
_visualizerFactory = visualizerFactory;
_logger = logger;
LoadScriptsCommand = new AsyncRelayCommand(LoadScriptsAsync);
ExecuteCommand = new AsyncRelayCommand(ExecuteScriptAsync, CanExecuteScript);
ExportCommand = new AsyncRelayCommand(ExportResultsAsync, CanExportResults);
CopySqlCommand = new RelayCommand(CopySqlToClipboard);
ClearResultsCommand = new RelayCommand(ClearResults);
SaveParametersCommand = new RelayCommand(SaveParameters);
LoadParametersCommand = new RelayCommand(LoadParameters);
// Подписка на события
_scriptManager.ScriptChanged += OnScriptChanged;
_scriptManager.ScriptsReloaded += OnScriptsReloaded;
}
private async Task LoadScriptsAsync()
{
try
{
IsBusy = true;
StatusMessage = "Загрузка скриптов...";
var scripts = await _scriptManager.LoadScriptsAsync();
_scripts.Clear();
foreach (var script in scripts)
{
_scripts.Add(script);
}
CategorizeScripts();
StatusMessage = $"Загружено {_scripts.Count} скриптов";
}
catch (Exception ex)
{
_logger.LogError(ex, "Error loading scripts");
StatusMessage = $"Ошибка загрузки: {ex.Message}";
}
finally
{
IsBusy = false;
}
}
private void CategorizeScripts()
{
_scriptCategories.Clear();
var categories = _scripts
.GroupBy(s => s.Category ?? "Без категории")
.OrderBy(g => g.Key);
foreach (var category in categories)
{
var scriptCategory = new ScriptCategory
{
Name = category.Key,
Scripts = new ObservableCollection<ScriptMetadata>(category.OrderBy(s => s.FileName))
};
_scriptCategories.Add(scriptCategory);
}
}
private void FilterScripts()
{
if (string.IsNullOrWhiteSpace(SearchText))
{
// Показать все скрипты
foreach (var category in _scriptCategories)
{
foreach (var script in category.Scripts)
{
script.IsVisible = true;
}
}
}
else
{
var searchLower = SearchText.ToLower();
foreach (var category in _scriptCategories)
{
foreach (var script in category.Scripts)
{
script.IsVisible =
script.FileName.ToLower().Contains(searchLower) ||
script.Description?.ToLower().Contains(searchLower) == true ||
script.Tags.Any(t => t.ToLower().Contains(searchLower));
}
}
}
}
private void OnSelectedScriptChanged()
{
Parameters.Clear();
if (_selectedScript == null) return;
// Создание ViewModel для каждого параметра
foreach (var param in _selectedScript.Parameters.OrderBy(p => p.Order))
{
var paramVm = new ParameterViewModel(param, _controlFactory);
paramVm.ValueChanged += OnParameterValueChanged;
Parameters.Add(paramVm);
}
// Восстановление сохраненных значений
LoadSavedParameters();
}
private void OnParameterValueChanged(object sender, EventArgs e)
{
ExecuteCommand.NotifyCanExecuteChanged();
// Обновление зависимых параметров
if (sender is ParameterViewModel changedParam)
{
UpdateDependentParameters(changedParam);
}
}
private void UpdateDependentParameters(ParameterViewModel changedParam)
{
foreach (var paramVm in Parameters)
{
if (paramVm.Parameter.DependsOn == changedParam.Parameter.Name)
{
paramVm.UpdateDependencies(GetCurrentParameterValues());
}
}
}
private Dictionary<string, object> GetCurrentParameterValues()
{
return Parameters.ToDictionary(
p => p.Parameter.Name,
p => p.Value ?? p.Parameter.DefaultValue);
}
private bool CanExecuteScript()
{
if (_selectedScript == null) return false;
// Проверка обязательных параметров
foreach (var paramVm in Parameters)
{
if (paramVm.Parameter.IsRequired &&
(paramVm.Value == null || string.IsNullOrWhiteSpace(paramVm.Value.ToString())))
{
return false;
}
}
return true;
}
private async Task ExecuteScriptAsync()
{
try
{
IsBusy = true;
StatusMessage = "Выполнение скрипта...";
var parameters = GetCurrentParameterValues();
var result = await _executionService.ExecuteAsync(_selectedScript, parameters);
// Добавление в историю
var historyItem = new ExecutionHistoryItem
{
ScriptId = _selectedScript.Id,
ScriptName = _selectedScript.FileName,
ExecutionTime = DateTime.Now,
Duration = result.ExecutionTime,
Success = result.IsSuccess,
Parameters = new Dictionary<string, object>(parameters),
RowCount = result.RowCount,
ErrorMessage = result.ErrorMessage,
ExecutedSql = result.ExecutedSql
};
_history.Insert(0, historyItem);
// Очистка старых записей истории
while (_history.Count > 1000)
{
_history.RemoveAt(_history.Count - 1);
}
if (result.IsSuccess)
{
CreateResultTabs(result);
StatusMessage = $"Выполнено за {result.ExecutionTime.TotalSeconds:F2} сек. Получено строк: {result.RowCount}";
}
else
{
StatusMessage = $"Ошибка: {result.ErrorMessage}";
ShowErrorDialog(result.ErrorMessage);
}
// Сохранение параметров
SaveParameters();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error executing script");
StatusMessage = $"Ошибка: {ex.Message}";
ShowErrorDialog(ex.Message);
}
finally
{
IsBusy = false;
}
}
private void CreateResultTabs(ExecutionResult result)
{
// Удаляем старые вкладки
ResultTabs.Clear();
for (int i = 0; i < result.Data.Tables.Count; i++)
{
var table = result.Data.Tables[i];
var outputDef = i < _selectedScript.Outputs.Count
? _selectedScript.Outputs[i]
: CreateDefaultOutputDefinition(table, i);
var visualizer = _visualizerFactory.GetVisualizer(outputDef.Type);
var content = visualizer.Visualize(table, outputDef);
var tabVm = new ResultTabViewModel
{
Title = outputDef.Description,
Content = content,
DataTable = table,
OutputDefinition = outputDef,
CanExport = true,
CanCopy = true
};
ResultTabs.Add(tabVm);
}
if (ResultTabs.Any())
{
SelectedResultTab = ResultTabs[0];
}
}
private OutputDefinition CreateDefaultOutputDefinition(DataTable table, int index)
{
return new OutputDefinition
{
Type = OutputType.Table,
Description = $"Результат {index + 1}",
DataTableName = table.TableName
};
}
private bool CanExportResults()
{
return SelectedResultTab != null &&
SelectedResultTab.DataTable != null &&
SelectedResultTab.DataTable.Rows.Count > 0;
}
private async Task ExportResultsAsync()
{
if (SelectedResultTab?.DataTable == null) return;
try
{
var savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
savePicker.FileTypeChoices.Add("Excel файл", new List<string> { ".xlsx" });
savePicker.FileTypeChoices.Add("CSV файл", new List<string> { ".csv" });
savePicker.FileTypeChoices.Add("JSON файл", new List<string> { ".json" });
savePicker.SuggestedFileName = $"{_selectedScript.FileName}_{DateTime.Now:yyyyMMdd_HHmmss}";
var file = await savePicker.PickSaveFileAsync();
if (file != null)
{
var options = new ExportOptions
{
Format = Path.GetExtension(file.Path).TrimStart('.').ToUpper(),
IncludeHeaders = true,
AutoFilter = true
};
await _exportService.ExportAsync(SelectedResultTab.DataTable, file.Path, options);
StatusMessage = $"Экспортировано в {file.Path}";
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error exporting results");
StatusMessage = $"Ошибка экспорта: {ex.Message}";
}
}
private void CopySqlToClipboard()
{
if (_selectedScript == null) return;
var parameters = GetCurrentParameterValues();
var sql = FormatSqlWithParameters(_selectedScript.ProcessedSql, parameters);
var package = new DataPackage();
package.SetText(sql);
Clipboard.SetContent(package);
StatusMessage = "SQL скопирован в буфер обмена";
}
private string FormatSqlWithParameters(string sql, Dictionary<string, object> parameters)
{
var result = new StringBuilder(sql);
foreach (var param in parameters)
{
var paramName = $"@{param.Key}";
var paramValue = FormatParameterForDisplay(param.Value);
result = result.Replace(paramName, paramValue);
}
return result.ToString();
}
private string FormatParameterForDisplay(object value)
{
if (value == null) return "NULL";
return value switch
{
string str => $"N'{str.Replace("'", "''")}'",
DateTime dt => $"'{dt:yyyy-MM-dd HH:mm:ss}'",
bool b => b ? "1" : "0",
_ => value.ToString()
};
}
private void ClearResults()
{
ResultTabs.Clear();
StatusMessage = "Результаты очищены";
}
private void SaveParameters()
{
if (_selectedScript == null) return;
var parameters = GetCurrentParameterValues();
var settings = ApplicationData.Current.LocalSettings;
var dict = new Dictionary<string, object>();
foreach (var param in parameters)
{
dict[param.Key] = param.Value;
}
var json = JsonSerializer.Serialize(dict);
settings.Values[$"ScriptParams_{_selectedScript.Id}"] = json;
StatusMessage = "Параметры сохранены";
}
private void LoadParameters()
{
if (_selectedScript == null) return;
var settings = ApplicationData.Current.LocalSettings;
if (settings.Values.TryGetValue($"ScriptParams_{_selectedScript.Id}", out var jsonObj))
{
try
{
var savedParams = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonObj.ToString());
foreach (var paramVm in Parameters)
{
if (savedParams.TryGetValue(paramVm.Parameter.Name, out var value))
{
paramVm.Value = value;
}
}
StatusMessage = "Параметры загружены";
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Error loading saved parameters");
}
}
}
private void ShowErrorDialog(string message)
{
// Реализация диалога ошибки
// Можно использовать ContentDialog или другое UI решение
}
private void OnScriptChanged(object sender, ScriptChangedEventArgs e)
{
// Обновление UI при изменении скрипта
DispatcherQueue.GetForCurrentThread().TryEnqueue(() =>
{
CategorizeScripts();
if (e.ChangeType == ScriptChangeType.Deleted &&
_selectedScript?.FullPath == e.FilePath)
{
SelectedScript = null;
}
});
}
private void OnScriptsReloaded(object sender, ScriptsReloadedEventArgs e)
{
DispatcherQueue.GetForCurrentThread().TryEnqueue(CategorizeScripts);
}
}

View File

@@ -0,0 +1,124 @@
using Microsoft.UI.Xaml;
using SQLVision.Core.Enums;
using SQLVision.Core.Interfaces;
using SQLVision.Core.Models;
using System;
using System.Collections.Generic;
using System.Linq;
namespace SQLVision.UI.ViewModels;
public class ParameterViewModel : ObservableObject
{
private readonly IControlFactory _controlFactory;
private FrameworkElement _control;
private object _value;
private bool _isEnabled = true;
private string _validationError;
public ScriptParameter Parameter { get; }
public string Name => Parameter.Name;
public string DisplayName => Parameter.DisplayName ?? Parameter.Name;
public string Description => Parameter.Description;
public ParameterType Type => Parameter.Type;
public FrameworkElement Control
{
get
{
if (_control == null)
{
_control = _controlFactory.CreateControl(Parameter, OnValueChanged);
}
return _control;
}
}
public object Value
{
get => _value ?? Parameter.DefaultValue;
set
{
if (SetProperty(ref _value, value))
{
ValidateValue();
ValueChanged?.Invoke(this, EventArgs.Empty);
}
}
}
public bool IsEnabled
{
get => _isEnabled;
set => SetProperty(ref _isEnabled, value);
}
public string ValidationError
{
get => _validationError;
private set => SetProperty(ref _validationError, value);
}
public bool HasError => !string.IsNullOrEmpty(ValidationError);
public event EventHandler ValueChanged;
public ParameterViewModel(ScriptParameter parameter, IControlFactory controlFactory)
{
Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter));
_controlFactory = controlFactory ?? throw new ArgumentNullException(nameof(controlFactory));
_value = parameter.DefaultValue;
}
private void OnValueChanged(object value)
{
Value = value;
}
private void ValidateValue()
{
if (Parameter.IsValid(Value))
{
ValidationError = null;
}
else
{
ValidationError = "Неверное значение параметра";
}
}
public void UpdateDependencies(Dictionary<string, object> currentValues)
{
if (string.IsNullOrEmpty(Parameter.DependsOn))
{
IsEnabled = true;
return;
}
if (!currentValues.TryGetValue(Parameter.DependsOn, out var dependencyValue))
{
IsEnabled = false;
return;
}
// Проверка условий зависимости
if (Parameter.DependencyValues != null)
{
var isEnabled = Parameter.DependencyValues
.Any(kvp => object.Equals(kvp.Value, dependencyValue));
IsEnabled = isEnabled;
}
else
{
IsEnabled = dependencyValue != null &&
!string.IsNullOrWhiteSpace(dependencyValue.ToString());
}
if (!IsEnabled)
{
Value = null;
}
}
}

View File

@@ -0,0 +1,70 @@
using Microsoft.UI.Xaml;
using SQLVision.Core.Models;
using System.Data;
namespace SQLVision.UI.ViewModels;
public class ResultTabViewModel : ObservableObject
{
private string _title;
private FrameworkElement _content;
private DataTable _dataTable;
private OutputDefinition _outputDefinition;
private bool _canExport;
private bool _canCopy;
public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
public FrameworkElement Content
{
get => _content;
set => SetProperty(ref _content, value);
}
public DataTable DataTable
{
get => _dataTable;
set => SetProperty(ref _dataTable, value);
}
public OutputDefinition OutputDefinition
{
get => _outputDefinition;
set => SetProperty(ref _outputDefinition, value);
}
public bool CanExport
{
get => _canExport;
set => SetProperty(ref _canExport, value);
}
public bool CanCopy
{
get => _canCopy;
set => SetProperty(ref _canCopy, value);
}
public IRelayCommand ExportCommand { get; }
public IRelayCommand CopyDataCommand { get; }
public ResultTabViewModel()
{
ExportCommand = new RelayCommand(Export);
CopyDataCommand = new RelayCommand(CopyData);
}
private void Export()
{
// Экспорт данных вкладки
}
private void CopyData()
{
// Копирование данных в буфер обмена
}
}

View File

@@ -0,0 +1,29 @@
using SQLVision.Core.Models;
using System.Collections.ObjectModel;
namespace SQLVision.UI.ViewModels;
public class ScriptCategory : ObservableObject
{
private string _name;
private ObservableCollection<ScriptMetadata> _scripts;
private bool _isExpanded = true;
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
public ObservableCollection<ScriptMetadata> Scripts
{
get => _scripts;
set => SetProperty(ref _scripts, value);
}
public bool IsExpanded
{
get => _isExpanded;
set => SetProperty(ref _isExpanded, value);
}
}