Добавьте файлы проекта.
This commit is contained in:
359
SQLVision.UI/Views/MainWindow.xaml
Normal file
359
SQLVision.UI/Views/MainWindow.xaml
Normal file
@@ -0,0 +1,359 @@
|
||||
<Window
|
||||
x:Class="SQLVision.UI.Views.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="using:SQLVision.UI.Controls"
|
||||
xmlns:charts="using:LiveChartsCore.SkiaSharpView.WinUI"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:converters="using:SQLVision.UI.Converters"
|
||||
mc:Ignorable="d"
|
||||
Title="SQLVision"
|
||||
Width="1200"
|
||||
Height="800"
|
||||
MinWidth="800"
|
||||
MinHeight="600">
|
||||
|
||||
<Window.Resources>
|
||||
<converters:BooleanToVisibilityConverter x:Key="BoolToVisibility"/>
|
||||
<converters:InverseBooleanConverter x:Key="InverseBool"/>
|
||||
|
||||
<Style TargetType="Button" x:Key="IconButtonStyle">
|
||||
<Setter Property="Margin" Value="2"/>
|
||||
<Setter Property="Padding" Value="8,4"/>
|
||||
<Setter Property="MinWidth" Value="80"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Панель инструментов -->
|
||||
<CommandBar Grid.Row="0" DefaultLabelPosition="Right">
|
||||
<AppBarButton
|
||||
Icon="Refresh"
|
||||
Label="Обновить скрипты"
|
||||
Command="{x:Bind ViewModel.LoadScriptsCommand}"/>
|
||||
<AppBarSeparator/>
|
||||
|
||||
<AppBarButton
|
||||
Icon="Play"
|
||||
Label="Выполнить"
|
||||
Command="{x:Bind ViewModel.ExecuteCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.ExecuteCommand.IsRunning, Converter={StaticResource InverseBool}, Mode=OneWay}"/>
|
||||
|
||||
<AppBarButton
|
||||
Icon="Save"
|
||||
Label="Экспорт"
|
||||
Command="{x:Bind ViewModel.ExportCommand}"/>
|
||||
|
||||
<AppBarButton
|
||||
Icon="Copy"
|
||||
Label="Копировать SQL"
|
||||
Command="{x:Bind ViewModel.CopySqlCommand}"/>
|
||||
|
||||
<AppBarSeparator/>
|
||||
|
||||
<AppBarButton
|
||||
Icon="Clear"
|
||||
Label="Очистить результаты"
|
||||
Command="{x:Bind ViewModel.ClearResultsCommand}"/>
|
||||
|
||||
<AppBarSeparator/>
|
||||
|
||||
<AppBarButton
|
||||
Icon="SaveLocal"
|
||||
Label="Сохранить параметры"
|
||||
Command="{x:Bind ViewModel.SaveParametersCommand}"/>
|
||||
|
||||
<AppBarButton
|
||||
Icon="OpenLocal"
|
||||
Label="Загрузить параметры"
|
||||
Command="{x:Bind ViewModel.LoadParametersCommand}"/>
|
||||
|
||||
<CommandBar.Content>
|
||||
<TextBlock
|
||||
Text="SQLVision"
|
||||
FontSize="18"
|
||||
FontWeight="SemiBold"
|
||||
Margin="12,0"/>
|
||||
</CommandBar.Content>
|
||||
</CommandBar>
|
||||
|
||||
<!-- Основное содержимое -->
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300" MinWidth="250"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Левая панель: скрипты и параметры -->
|
||||
<Grid Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Поиск -->
|
||||
<AutoSuggestBox
|
||||
Grid.Row="0"
|
||||
PlaceholderText="Поиск скриптов..."
|
||||
Text="{x:Bind ViewModel.SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="8">
|
||||
<AutoSuggestBox.QueryIcon>
|
||||
<SymbolIcon Symbol="Find"/>
|
||||
</AutoSuggestBox.QueryIcon>
|
||||
</AutoSuggestBox>
|
||||
|
||||
<!-- Дерево скриптов -->
|
||||
<TreeView
|
||||
Grid.Row="1"
|
||||
ItemsSource="{x:Bind ViewModel.ScriptCategories, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedScript, Mode=TwoWay}"
|
||||
Margin="8">
|
||||
|
||||
<TreeView.ItemTemplate>
|
||||
<DataTemplate x:DataType="viewmodels:ScriptCategory">
|
||||
<TreeViewItem
|
||||
ItemsSource="{x:Bind Scripts}"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}">
|
||||
|
||||
<TreeViewItem.Header>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="{x:Bind Name}" FontWeight="SemiBold"/>
|
||||
<TextBlock
|
||||
Text="{x:Bind Scripts.Count}"
|
||||
Foreground="Gray"
|
||||
FontSize="12"/>
|
||||
</StackPanel>
|
||||
</TreeViewItem.Header>
|
||||
|
||||
<TreeViewItem.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:ScriptMetadata">
|
||||
<TreeViewItem>
|
||||
<StackPanel Orientation="Vertical" Spacing="2">
|
||||
<TextBlock
|
||||
Text="{x:Bind FileName}"
|
||||
TextWrapping="Wrap"
|
||||
FontWeight="Normal"/>
|
||||
<TextBlock
|
||||
Text="{x:Bind Description}"
|
||||
FontSize="11"
|
||||
Foreground="Gray"
|
||||
TextWrapping="Wrap"
|
||||
MaxLines="2"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</DataTemplate>
|
||||
</TreeViewItem.ItemTemplate>
|
||||
</TreeViewItem>
|
||||
</DataTemplate>
|
||||
</TreeView.ItemTemplate>
|
||||
</TreeView>
|
||||
|
||||
<!-- Параметры скрипта -->
|
||||
<Border
|
||||
Grid.Row="2"
|
||||
BorderBrush="{ThemeResource SystemControlForegroundBaseLowBrush}"
|
||||
BorderThickness="0,1,0,0"
|
||||
Padding="8"
|
||||
MaxHeight="400">
|
||||
|
||||
<ScrollViewer>
|
||||
<StackPanel
|
||||
x:Name="ParametersPanel"
|
||||
Spacing="12"
|
||||
Visibility="{x:Bind ViewModel.SelectedScript, Converter={StaticResource NullToVisibilityConverter}, Mode=OneWay}">
|
||||
|
||||
<TextBlock
|
||||
Text="Параметры"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Margin="0,0,0,8"/>
|
||||
|
||||
<ItemsControl ItemsSource="{x:Bind ViewModel.Parameters, Mode=OneWay}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="viewmodels:ParameterViewModel">
|
||||
<StackPanel Spacing="4" Margin="0,0,0,8">
|
||||
<ContentPresenter Content="{x:Bind Control}"/>
|
||||
|
||||
<TextBlock
|
||||
Text="{x:Bind ValidationError}"
|
||||
Foreground="Red"
|
||||
FontSize="11"
|
||||
Visibility="{x:Bind HasError, Converter={StaticResource BoolToVisibility}}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- Splitter -->
|
||||
<GridSplitter
|
||||
Grid.Column="1"
|
||||
Width="4"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="Transparent"/>
|
||||
|
||||
<!-- Правая панель: результаты -->
|
||||
<Grid Grid.Column="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Вкладки с результатами -->
|
||||
<muxc:TabView
|
||||
Grid.Row="0"
|
||||
ItemsSource="{x:Bind ViewModel.ResultTabs, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedResultTab, Mode=TwoWay}"
|
||||
TabWidthMode="SizeToContent"
|
||||
CanReorderTabs="True"
|
||||
CanCloseTabs="True"
|
||||
TabCloseRequested="OnTabCloseRequested">
|
||||
|
||||
<muxc:TabView.TabItemTemplate>
|
||||
<DataTemplate x:DataType="viewmodels:ResultTabViewModel">
|
||||
<muxc:TabViewItem
|
||||
Header="{x:Bind Title}"
|
||||
IconSource="{x:Bind IconSource}">
|
||||
|
||||
<ScrollViewer
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<ContentPresenter Content="{x:Bind Content}"/>
|
||||
</ScrollViewer>
|
||||
|
||||
<muxc:TabViewItem.ContextFlyout>
|
||||
<MenuFlyout>
|
||||
<MenuFlyoutItem
|
||||
Text="Экспорт"
|
||||
Command="{x:Bind ExportCommand}"
|
||||
Icon="Save"/>
|
||||
<MenuFlyoutItem
|
||||
Text="Копировать данные"
|
||||
Command="{x:Bind CopyDataCommand}"
|
||||
Icon="Copy"/>
|
||||
<MenuFlyoutSeparator/>
|
||||
<MenuFlyoutItem
|
||||
Text="Закрыть"
|
||||
Click="OnCloseTabClick"/>
|
||||
</MenuFlyout>
|
||||
</muxc:TabViewItem.ContextFlyout>
|
||||
</muxc:TabViewItem>
|
||||
</DataTemplate>
|
||||
</muxc:TabView.TabItemTemplate>
|
||||
</muxc:TabView>
|
||||
|
||||
<!-- Панель истории -->
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Visibility="{x:Bind ViewModel.History.Count, Converter={StaticResource CountToVisibilityConverter}, Mode=OneWay}">
|
||||
|
||||
<Expander
|
||||
Header="История выполненных запросов"
|
||||
IsExpanded="False"
|
||||
Margin="8">
|
||||
|
||||
<ListView
|
||||
ItemsSource="{x:Bind ViewModel.History, Mode=OneWay}"
|
||||
MaxHeight="200"
|
||||
SelectionMode="None">
|
||||
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:ExecutionHistoryItem">
|
||||
<Grid Padding="8" BorderBrush="LightGray" BorderThickness="0,0,0,1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock
|
||||
Text="{x:Bind ScriptName}"
|
||||
FontWeight="SemiBold"/>
|
||||
<TextBlock
|
||||
Text="{x:Bind ExecutionTime, StringFormat='{}{0:dd.MM.yyyy HH:mm:ss}'}"
|
||||
FontSize="11"
|
||||
Foreground="Gray"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Text="{x:Bind Duration, StringFormat='{}{0:mm\\:ss}'}"
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"/>
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="2"
|
||||
Text="{x:Bind RowCount, StringFormat='{}Строк: {0}'}"
|
||||
VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</Expander>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Статус бар -->
|
||||
<StatusBar Grid.Row="2">
|
||||
<StatusBarItem>
|
||||
<ProgressRing
|
||||
Width="16"
|
||||
Height="16"
|
||||
IsActive="{x:Bind ViewModel.IsBusy, Mode=OneWay}"/>
|
||||
</StatusBarItem>
|
||||
|
||||
<StatusBarItem>
|
||||
<TextBlock Text="{x:Bind ViewModel.StatusMessage, Mode=OneWay}"/>
|
||||
</StatusBarItem>
|
||||
|
||||
<StatusBarItem HorizontalAlignment="Right">
|
||||
<TextBlock>
|
||||
<Run Text="Скриптов:"/>
|
||||
<Run Text="{x:Bind ViewModel.ScriptCategories.Sum(c => c.Scripts.Count), Mode=OneWay}"/>
|
||||
<Run Text="|"/>
|
||||
<Run Text="Вкладок:"/>
|
||||
<Run Text="{x:Bind ViewModel.ResultTabs.Count, Mode=OneWay}"/>
|
||||
</TextBlock>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
|
||||
<!-- Прогресс выполнения -->
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="3"
|
||||
Background="#CC000000"
|
||||
Visibility="{x:Bind ViewModel.IsBusy, Converter={StaticResource BoolToVisibility}, Mode=OneWay}">
|
||||
|
||||
<Border
|
||||
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="24"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
|
||||
<StackPanel Spacing="16" HorizontalAlignment="Center">
|
||||
<ProgressRing Width="40" Height="40" IsActive="True"/>
|
||||
<TextBlock
|
||||
Text="Выполнение запроса..."
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
169
SQLVision.UI/Views/MainWindow.xaml.cs
Normal file
169
SQLVision.UI/Views/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,169 @@
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using SQLVision.Core.Models;
|
||||
using SQLVision.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Windows.Graphics;
|
||||
|
||||
namespace SQLVision.UI.Views
|
||||
{
|
||||
public sealed partial class MainWindow : Window
|
||||
{
|
||||
// Õðàíèì òåêóùèå ìåòàäàííûå âûáðàííîãî ñêðèïòà
|
||||
private ScriptMetadata currentMetadata;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
SetWindowSize(1200, 800);
|
||||
LoadScripts();
|
||||
}
|
||||
|
||||
private void SetWindowSize(int width, int height)
|
||||
{
|
||||
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
|
||||
var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hwnd);
|
||||
var appWindow = AppWindow.GetFromWindowId(windowId);
|
||||
appWindow.Resize(new SizeInt32(width, height));
|
||||
}
|
||||
|
||||
private void LoadScripts()
|
||||
{
|
||||
var folder = Path.Combine(AppContext.BaseDirectory, "Scripts");
|
||||
if (!Directory.Exists(folder)) return;
|
||||
|
||||
foreach (var file in Directory.GetFiles(folder, "*.sql", SearchOption.AllDirectories))
|
||||
{
|
||||
var node = new TreeViewNode
|
||||
{
|
||||
Content = new ScriptTreeItem
|
||||
{
|
||||
DisplayName = Path.GetFileName(file),
|
||||
FilePath = file
|
||||
}
|
||||
};
|
||||
ScriptsTree.RootNodes.Add(node);
|
||||
}
|
||||
|
||||
ScriptsTree.ItemInvoked += ScriptsTree_ItemInvoked;
|
||||
}
|
||||
|
||||
private void ScriptsTree_ItemInvoked(TreeView sender, TreeViewItemInvokedEventArgs args)
|
||||
{
|
||||
if (args.InvokedItem is TreeViewNode node && node.Content is ScriptTreeItem item)
|
||||
{
|
||||
var file = item.FilePath;
|
||||
var lines = File.ReadAllLines(file);
|
||||
var parser = new SqlScriptParser();
|
||||
currentMetadata = parser.Parse(lines); // ñîõðàíÿåì â ïîëå
|
||||
|
||||
RenderParameters(currentMetadata);
|
||||
|
||||
OutputTabs.TabItems.Clear();
|
||||
foreach (var output in currentMetadata.Outputs)
|
||||
{
|
||||
var tab = new TabViewItem
|
||||
{
|
||||
Header = output.Description,
|
||||
Content = new TextBlock { Text = $"Âûâîä: {output.Type}" }
|
||||
};
|
||||
OutputTabs.TabItems.Add(tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderParameters(ScriptMetadata metadata)
|
||||
{
|
||||
ParametersPanel.Items.Clear();
|
||||
|
||||
foreach (var param in metadata.Parameters)
|
||||
{
|
||||
FrameworkElement control = null;
|
||||
|
||||
switch (param.Type)
|
||||
{
|
||||
case ParameterType.Int:
|
||||
control = new TextBox { Header = param.Description, Text = param.DefaultValue ?? string.Empty };
|
||||
break;
|
||||
case ParameterType.String:
|
||||
control = new TextBox { Header = param.Description, Text = param.DefaultValue ?? string.Empty };
|
||||
break;
|
||||
case ParameterType.DateTime:
|
||||
control = new DatePicker
|
||||
{
|
||||
Header = param.Description,
|
||||
SelectedDate = DateTime.TryParse(param.DefaultValue, out var dt) ? dt : DateTime.Now
|
||||
};
|
||||
break;
|
||||
case ParameterType.Bool:
|
||||
control = new CheckBox
|
||||
{
|
||||
Content = param.Description,
|
||||
IsChecked = param.DefaultValue?.ToLower() == "true"
|
||||
};
|
||||
break;
|
||||
case ParameterType.Table:
|
||||
var combo = new ComboBox { Header = param.Description };
|
||||
combo.Items.Add("Ìàãàçèí 1");
|
||||
combo.Items.Add("Ìàãàçèí 2");
|
||||
combo.Items.Add("Ìàãàçèí 3");
|
||||
control = combo;
|
||||
break;
|
||||
}
|
||||
|
||||
param.Control = control;
|
||||
ParametersPanel.Items.Add(control);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, object> CollectParameterValues()
|
||||
{
|
||||
var values = new Dictionary<string, object>();
|
||||
|
||||
if (currentMetadata == null) return values;
|
||||
|
||||
foreach (var param in currentMetadata.Parameters)
|
||||
{
|
||||
switch (param.Type)
|
||||
{
|
||||
case ParameterType.Int:
|
||||
if (param.Control is TextBox tbInt && int.TryParse(tbInt.Text, out var intVal))
|
||||
values[param.Name] = intVal;
|
||||
break;
|
||||
case ParameterType.String:
|
||||
if (param.Control is TextBox tbStr)
|
||||
values[param.Name] = tbStr.Text;
|
||||
break;
|
||||
case ParameterType.DateTime:
|
||||
if (param.Control is DatePicker dp && dp.SelectedDate.HasValue)
|
||||
values[param.Name] = dp.SelectedDate.Value;
|
||||
break;
|
||||
case ParameterType.Bool:
|
||||
if (param.Control is CheckBox cb)
|
||||
values[param.Name] = cb.IsChecked ?? false;
|
||||
break;
|
||||
case ParameterType.Table:
|
||||
if (param.Control is ComboBox combo && combo.SelectedItem != null)
|
||||
values[param.Name] = combo.SelectedItem.ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private void ExecuteButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var values = CollectParameterValues();
|
||||
|
||||
// Çäåñü ìîæíî ñôîðìèðîâàòü SQL ñ ïîäñòàíîâêîé ïàðàìåòðîâ
|
||||
foreach (var kv in values)
|
||||
{
|
||||
Console.WriteLine($"{kv.Key} = {kv.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user