fix(pos-ui): выравнивание по замечаниям (кнопки, клавиатура, модалка, правая панель)

- Текст во ВСЕХ кнопках по центру: HorizontalAlignment=Stretch + Horizontal/
  VerticalContentAlignment=Center в стилях Button.pos/key/seg (раньше key/seg не
  наследовали центровку → цифры/«−/+»/«Сброс»/«⌫» липли влево-вверх).
- Клавиатура оплаты — ровная сетка 3×4 одинаковых крупных клавиш (72px), цифры по центру.
- Быстрые суммы и сегменты «Нал/Карта/Смешанная» — UniformGrid одинаковой ширины;
  сегменты слитным переключателем; «Без сдачи» не обрезается.
- Модалка оплаты по высоте содержимого, по центру, на затемнённой подложке (#0F1F17 ~40%).
- Правая панель: ровная 2-кол. сетка вторичных кнопок; добавлены «Возврат · F9» и
  «Внесение/Выплата · F10»; «Очистить · Esc» — красный контур во всю ширину; без пустот
  (блок компактный, Оплатить сразу под ИТОГО).
- Строка корзины: степпер 44×44 с количеством по центру, отступ до иконки удаления.
- Экран продажи снимается С ОБОЛОЧКОЙ (верхняя полоса + капсулы горячих клавиш);
  «Избранное» — шеврон ▾/▸. --uitest OK, 44 unit зелёные.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
nns 2026-10-08 13:46:17 +05:00
parent ac55da8d06
commit 29ef76990e
28 changed files with 121 additions and 69 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 130 KiB

File diff suppressed because one or more lines are too long

View file

@ -45,6 +45,7 @@
<Setter Property="Foreground" Value="{DynamicResource PosText}"/>
<Setter Property="BorderBrush" Value="{DynamicResource PosBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
<Style Selector="Button.pos /template/ ContentPresenter">
<Setter Property="Transitions">
@ -101,6 +102,14 @@
<Setter Property="CornerRadius" Value="12"/>
<Setter Property="BorderBrush" Value="{DynamicResource PosBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style Selector="Button.key /template/ ContentPresenter">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style Selector="Button.key:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource PosSubtle}"/>
@ -111,6 +120,13 @@
<Setter Property="Background" Value="{DynamicResource PosCard}"/>
<Setter Property="Foreground" Value="{DynamicResource PosText}"/>
<Setter Property="Height" Value="52"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style Selector="Button.seg /template/ ContentPresenter">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style Selector="Button.seg.on">
<Setter Property="Background" Value="{DynamicResource PosBrand}"/>

View file

@ -33,10 +33,10 @@ public static int Run(string[] args)
new("01-login", "Вход кассира (адрес сервера, логин, пароль)", () => new LoginView { DataContext = LoginViewModel.Sample() }),
new("01b-login-pin", "Быстрый вход по PIN (зарегистрированное устройство)", () => new LoginView { DataContext = LoginViewModel.SamplePin() }),
new("02-shift-open", "Смена: Z-отчёт/состояние смены", () => new ShiftView { DataContext = ShiftViewModel.Sample() }),
new("03-sale-empty", "Продажа: пустой чек, ожидание сканирования", () => new SaleView { DataContext = new SaleViewModel() }),
new("04-sale-items", "Продажа: чек с товарами (вкл. весовой)", () => new SaleView { DataContext = SaleViewModel.Sample() }),
new("05-payment-cash", "Оплата наличными со сдачей", () => new PaymentView { DataContext = PaymentViewModel.SampleCash() }),
new("06-payment-mixed", "Оплата смешанная (нал+карта)", () => new PaymentView { DataContext = PaymentViewModel.SampleMixed() }),
new("03-sale-empty", "Продажа: пустой чек, ожидание сканирования (с оболочкой)", () => ShellWith(EmptySale())),
new("04-sale-items", "Продажа: чек с товарами + избранное (с оболочкой)", () => new MainWindow { DataContext = new MainWindowViewModel() }),
new("05-payment-cash", "Оплата наличными со сдачей", () => PayScrim(PaymentViewModel.SampleCash())),
new("06-payment-mixed", "Оплата смешанная (нал+карта)", () => PayScrim(PaymentViewModel.SampleMixed())),
new("07-return", "Возврат по чеку (выбор позиций)", () => new ReturnView { DataContext = ReturnViewModel.Sample() }),
new("08-shift-z", "Z-отчёт при закрытии (должно/факт/разница)", () => new ShiftView { DataContext = ShiftViewModel.SampleClosed() }),
new("09-shell-offline", "Статус-бар: нет связи, чеки в очереди", () => ShellOffline()),
@ -71,6 +71,26 @@ public static int Run(string[] args)
return 0;
}
private static SaleViewModel EmptySale() => new();
private static Control ShellWith(SaleViewModel sale)
{
var vm = new MainWindowViewModel();
vm.CurrentPage = sale;
return new MainWindow { DataContext = vm };
}
/// <summary>Модальная оплата на затемнённой подложке (как в оболочке):
/// светлый фон → полупрозрачная тёмная подложка → белое модальное окно.</summary>
private static Control PayScrim(PaymentViewModel pay)
=> new Border
{
Background = new Avalonia.Media.SolidColorBrush(Avalonia.Media.Color.Parse("#F4F6F5")),
Child = new Border
{
Background = new Avalonia.Media.SolidColorBrush(Avalonia.Media.Color.Parse("#660F1F17")),
Child = new PaymentView { DataContext = pay },
},
};
private static Control ShellOffline()
{
var vm = new MainWindowViewModel { IsOnline = false, QueueCount = 3, CashierName = "Пётр Кассиров", ShiftNumber = "С-2026-000001" };

View file

@ -55,7 +55,12 @@ private void StartSession()
{
CashierName = _svc!.Session?.CashierName ?? "кассир";
QueueCount = _svc.Store.PendingCount();
_sale = new SaleViewModel(_svc) { PaymentRequested = OpenPayment, SaleCommitted = _ => RefreshStatus() };
_sale = new SaleViewModel(_svc)
{
PaymentRequested = OpenPayment, SaleCommitted = _ => RefreshStatus(),
NavReturnRequested = () => ShowReturnCommand.Execute(null),
NavShiftRequested = () => ShowShiftCommand.Execute(null),
};
CurrentPage = _sale;
StartSyncLoop();
_ = CheckForUpdateAsync();
@ -398,6 +403,12 @@ public partial class SaleViewModel : ViewModelBase
public Action<PaymentViewModel>? PaymentRequested;
/// <summary>Чек проведён — оболочка обновляет индикатор очереди.</summary>
public Action<CheckoutService.CommitResult>? SaleCommitted;
/// <summary>Переходы к возврату/смене (обрабатывает оболочка — те же, что F9/F7/F10).</summary>
public Action? NavReturnRequested;
public Action? NavShiftRequested;
[RelayCommand] private void GoReturn() => NavReturnRequested?.Invoke();
[RelayCommand] private void GoShift() => NavShiftRequested?.Invoke();
public SaleViewModel() { }
public SaleViewModel(AppServices svc) { _svc = svc; LoadFavorites(); }

View file

@ -3,7 +3,7 @@
xmlns:vm="clr-namespace:foodmarket.Pos.ViewModels"
x:Class="foodmarket.Pos.Views.PaymentView"
x:DataType="vm:PaymentViewModel">
<Border Classes="card" Width="760" Padding="28" CornerRadius="18">
<Border Classes="card" Width="720" Padding="28" CornerRadius="18" VerticalAlignment="Center" HorizontalAlignment="Center">
<StackPanel Spacing="16">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Text="Оплата" FontSize="22" FontWeight="Bold" Foreground="{DynamicResource PosText}" VerticalAlignment="Center"/>
@ -13,14 +13,16 @@
</StackPanel>
</Grid>
<!-- Сегменты способа оплаты -->
<Grid ColumnDefinitions="*,*,*">
<Button Classes="pos seg" Classes.on="{Binding IsCash}" Margin="0,0,5,0" Content="Наличные" Command="{Binding SelectCashCommand}"/>
<Button Grid.Column="1" Classes="pos seg" Classes.on="{Binding IsCard}" Margin="5,0" Content="Карта" Command="{Binding SelectCardCommand}"/>
<Button Grid.Column="2" Classes="pos seg" Classes.on="{Binding IsMixed}" Margin="5,0,0,0" Content="Смешанная" Command="{Binding SelectMixedCommand}"/>
</Grid>
<!-- Сегменты способа оплаты (слитный переключатель) -->
<Border Background="{DynamicResource PosSubtle}" CornerRadius="12" Padding="4">
<UniformGrid Columns="3">
<Button Classes="pos seg" Classes.on="{Binding IsCash}" Margin="2" Content="Наличные" Command="{Binding SelectCashCommand}"/>
<Button Classes="pos seg" Classes.on="{Binding IsCard}" Margin="2" Content="Карта" Command="{Binding SelectCardCommand}"/>
<Button Classes="pos seg" Classes.on="{Binding IsMixed}" Margin="2" Content="Смешанная" Command="{Binding SelectMixedCommand}"/>
</UniformGrid>
</Border>
<Grid ColumnDefinitions="*,320">
<Grid ColumnDefinitions="*,300">
<!-- Левая часть: суммы -->
<StackPanel Grid.Column="0" Spacing="12" Margin="0,0,20,0">
<StackPanel Spacing="4">
@ -32,14 +34,14 @@
<TextBox Classes="pos" FontSize="24" Text="{Binding PaidCard}"/>
</StackPanel>
<!-- Быстрые суммы -->
<Grid ColumnDefinitions="*,*,*" RowDefinitions="Auto,Auto" IsVisible="{Binding !IsCard}">
<Button Classes="pos ghost" Margin="0,0,4,8" Content="Без сдачи" Command="{Binding QuickCashCommand}" CommandParameter="exact"/>
<Button Grid.Column="1" Classes="pos ghost" Margin="4,0,4,8" Content="1 000" Command="{Binding QuickCashCommand}" CommandParameter="1000"/>
<Button Grid.Column="2" Classes="pos ghost" Margin="4,0,0,8" Content="2 000" Command="{Binding QuickCashCommand}" CommandParameter="2000"/>
<Button Grid.Row="1" Classes="pos ghost" Margin="0,0,4,0" Content="5 000" Command="{Binding QuickCashCommand}" CommandParameter="5000"/>
<Button Grid.Row="1" Grid.Column="1" Classes="pos ghost" Margin="4,0" Content="10 000" Command="{Binding QuickCashCommand}" CommandParameter="10000"/>
<Button Grid.Row="1" Grid.Column="2" Classes="pos ghost" Margin="4,0,0,0" Content="20 000" Command="{Binding QuickCashCommand}" CommandParameter="20000"/>
</Grid>
<UniformGrid Columns="3" IsVisible="{Binding !IsCard}">
<Button Classes="pos ghost" Margin="3" FontSize="14.5" Padding="4,0" Content="Без сдачи" Command="{Binding QuickCashCommand}" CommandParameter="exact"/>
<Button Classes="pos ghost" Margin="3" Content="1 000" Command="{Binding QuickCashCommand}" CommandParameter="1000"/>
<Button Classes="pos ghost" Margin="3" Content="2 000" Command="{Binding QuickCashCommand}" CommandParameter="2000"/>
<Button Classes="pos ghost" Margin="3" Content="5 000" Command="{Binding QuickCashCommand}" CommandParameter="5000"/>
<Button Classes="pos ghost" Margin="3" Content="10 000" Command="{Binding QuickCashCommand}" CommandParameter="10000"/>
<Button Classes="pos ghost" Margin="3" Content="20 000" Command="{Binding QuickCashCommand}" CommandParameter="20000"/>
</UniformGrid>
<!-- Сдача -->
<Border Background="{DynamicResource PosBrandSoft}" CornerRadius="12" Padding="16,14">
@ -50,21 +52,21 @@
</Border>
</StackPanel>
<!-- Правая часть: цифровая клавиатура -->
<Grid Grid.Column="1" ColumnDefinitions="*,*,*" RowDefinitions="*,*,*,*" IsVisible="{Binding !IsCard}">
<Button Grid.Row="0" Grid.Column="0" Classes="key" Margin="3" Height="54" Content="1" Command="{Binding KeyDigitCommand}" CommandParameter="1"/>
<Button Grid.Row="0" Grid.Column="1" Classes="key" Margin="3" Height="54" Content="2" Command="{Binding KeyDigitCommand}" CommandParameter="2"/>
<Button Grid.Row="0" Grid.Column="2" Classes="key" Margin="3" Height="54" Content="3" Command="{Binding KeyDigitCommand}" CommandParameter="3"/>
<Button Grid.Row="1" Grid.Column="0" Classes="key" Margin="3" Height="54" Content="4" Command="{Binding KeyDigitCommand}" CommandParameter="4"/>
<Button Grid.Row="1" Grid.Column="1" Classes="key" Margin="3" Height="54" Content="5" Command="{Binding KeyDigitCommand}" CommandParameter="5"/>
<Button Grid.Row="1" Grid.Column="2" Classes="key" Margin="3" Height="54" Content="6" Command="{Binding KeyDigitCommand}" CommandParameter="6"/>
<Button Grid.Row="2" Grid.Column="0" Classes="key" Margin="3" Height="54" Content="7" Command="{Binding KeyDigitCommand}" CommandParameter="7"/>
<Button Grid.Row="2" Grid.Column="1" Classes="key" Margin="3" Height="54" Content="8" Command="{Binding KeyDigitCommand}" CommandParameter="8"/>
<Button Grid.Row="2" Grid.Column="2" Classes="key" Margin="3" Height="54" Content="9" Command="{Binding KeyDigitCommand}" CommandParameter="9"/>
<Button Grid.Row="3" Grid.Column="0" Classes="key" Margin="3" Height="54" FontSize="15" Content="Сброс" Command="{Binding KeyClearCommand}"/>
<Button Grid.Row="3" Grid.Column="1" Classes="key" Margin="3" Height="54" Content="0" Command="{Binding KeyDigitCommand}" CommandParameter="0"/>
<Button Grid.Row="3" Grid.Column="2" Classes="key" Margin="3" Height="54" FontSize="18" Content="⌫" Command="{Binding KeyBackCommand}"/>
</Grid>
<!-- Правая часть: цифровая клавиатура 3×4 (ровные квадраты) -->
<UniformGrid Grid.Column="1" Columns="3" Rows="4" VerticalAlignment="Top" IsVisible="{Binding !IsCard}">
<Button Classes="key" Margin="4" Height="72" Content="1" Command="{Binding KeyDigitCommand}" CommandParameter="1"/>
<Button Classes="key" Margin="4" Height="72" Content="2" Command="{Binding KeyDigitCommand}" CommandParameter="2"/>
<Button Classes="key" Margin="4" Height="72" Content="3" Command="{Binding KeyDigitCommand}" CommandParameter="3"/>
<Button Classes="key" Margin="4" Height="72" Content="4" Command="{Binding KeyDigitCommand}" CommandParameter="4"/>
<Button Classes="key" Margin="4" Height="72" Content="5" Command="{Binding KeyDigitCommand}" CommandParameter="5"/>
<Button Classes="key" Margin="4" Height="72" Content="6" Command="{Binding KeyDigitCommand}" CommandParameter="6"/>
<Button Classes="key" Margin="4" Height="72" Content="7" Command="{Binding KeyDigitCommand}" CommandParameter="7"/>
<Button Classes="key" Margin="4" Height="72" Content="8" Command="{Binding KeyDigitCommand}" CommandParameter="8"/>
<Button Classes="key" Margin="4" Height="72" Content="9" Command="{Binding KeyDigitCommand}" CommandParameter="9"/>
<Button Classes="key" Margin="4" Height="72" FontSize="15" Content="Сброс" Command="{Binding KeyClearCommand}"/>
<Button Classes="key" Margin="4" Height="72" Content="0" Command="{Binding KeyDigitCommand}" CommandParameter="0"/>
<Button Classes="key" Margin="4" Height="72" FontSize="20" Content="⌫" Command="{Binding KeyBackCommand}"/>
</UniformGrid>
</Grid>
<Button Classes="pos primary" HorizontalAlignment="Stretch" Height="66" FontSize="20" Command="{Binding ConfirmCommand}" IsDefault="True" IsEnabled="{Binding Sufficient}">

View file

@ -22,10 +22,13 @@
<!-- Избранное (быстрые товары) -->
<StackPanel Grid.Row="1" Spacing="8" Margin="0,0,0,14" IsVisible="{Binding HasFavorites}">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Text="Избранное" Foreground="{DynamicResource PosTextMuted}" FontSize="13.5" FontWeight="Medium" VerticalAlignment="Center"/>
<Button Grid.Column="1" Classes="pos ghost" Height="30" Padding="10,0" FontSize="12.5" Content="Свернуть/развернуть" Command="{Binding ToggleFavoritesCommand}"/>
</Grid>
<Button Classes="pos ghost" HorizontalAlignment="Left" Height="32" Padding="12,0" FontSize="13.5" Command="{Binding ToggleFavoritesCommand}" BorderThickness="0" Background="Transparent">
<StackPanel Orientation="Horizontal" Spacing="6">
<PathIcon Width="12" Height="12" Foreground="{DynamicResource PosTextMuted}" IsVisible="{Binding FavoritesOpen}" Data="M7 10l5 5 5-5z"/>
<PathIcon Width="12" Height="12" Foreground="{DynamicResource PosTextMuted}" IsVisible="{Binding !FavoritesOpen}" Data="M10 17l5-5-5-5z"/>
<TextBlock Text="Избранное" Foreground="{DynamicResource PosTextMuted}" FontWeight="Medium"/>
</StackPanel>
</Button>
<ItemsControl ItemsSource="{Binding Favorites}" IsVisible="{Binding FavoritesOpen}">
<ItemsControl.ItemsPanel><ItemsPanelTemplate><UniformGrid Columns="3"/></ItemsPanelTemplate></ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
@ -45,7 +48,7 @@
<!-- Корзина -->
<Border Grid.Row="2" Classes="card" Padding="0">
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" ColumnDefinitions="*,170,120,44" Height="40" Margin="18,6,10,0">
<Grid Grid.Row="0" ColumnDefinitions="*,180,120,52" Height="40" Margin="18,6,10,0">
<TextBlock Text="Товар" Foreground="{DynamicResource PosTextMuted}" FontSize="13" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="Количество" Foreground="{DynamicResource PosTextMuted}" FontSize="13" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Grid.Column="2" Text="Сумма" Foreground="{DynamicResource PosTextMuted}" FontSize="13" HorizontalAlignment="Right" VerticalAlignment="Center"/>
@ -68,22 +71,22 @@
<ListBox.ItemTemplate>
<DataTemplate x:DataType="vm:SaleLineVm">
<Border Background="{DynamicResource PosSubtle}" CornerRadius="10" Padding="12,8">
<Grid ColumnDefinitions="*,170,120,40">
<Grid ColumnDefinitions="*,180,120,52">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="{Binding Name}" Foreground="{DynamicResource PosText}" FontSize="17" FontWeight="Medium" TextWrapping="Wrap"/>
<TextBlock Text="{Binding DiscountText}" Foreground="{DynamicResource PosBrand}" FontSize="13" IsVisible="{Binding HasDiscount}"/>
<TextBlock Text="{Binding Price, StringFormat='{}{0:N0} ₸ / ед.'}" Foreground="{DynamicResource PosTextMuted}" FontSize="13" IsVisible="{Binding !HasDiscount}"/>
</StackPanel>
<!-- Степпер -->
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="6" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Classes="key" Width="40" Height="40" Padding="0" FontSize="22" Content="−"
<!-- Степпер 44×44 -->
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="8" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Classes="key" Width="44" Height="44" FontSize="22" Content="−"
Command="{Binding $parent[ItemsControl].((vm:SaleViewModel)DataContext).DecLineCommand}" CommandParameter="{Binding}"/>
<TextBlock Text="{Binding QtyText}" Foreground="{DynamicResource PosText}" FontSize="16" FontWeight="SemiBold" MinWidth="58" TextAlignment="Center" VerticalAlignment="Center"/>
<Button Classes="key" Width="40" Height="40" Padding="0" FontSize="20" Content="+"
<TextBlock Text="{Binding QtyText}" Foreground="{DynamicResource PosText}" FontSize="16" FontWeight="SemiBold" MinWidth="56" TextAlignment="Center" VerticalAlignment="Center"/>
<Button Classes="key" Width="44" Height="44" FontSize="20" Content="+"
Command="{Binding $parent[ItemsControl].((vm:SaleViewModel)DataContext).IncLineCommand}" CommandParameter="{Binding}"/>
</StackPanel>
<TextBlock Grid.Column="2" Text="{Binding LineTotal, StringFormat='{}{0:N0} ₸'}" Foreground="{DynamicResource PosText}" FontSize="19" FontWeight="SemiBold" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<Button Grid.Column="3" Classes="key" Width="34" Height="34" Padding="0" Background="Transparent" BorderThickness="0" VerticalAlignment="Center"
<Button Grid.Column="3" Classes="key" Width="36" Height="36" Background="Transparent" BorderThickness="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="12,0,0,0"
Command="{Binding $parent[ItemsControl].((vm:SaleViewModel)DataContext).RemoveLineCommand}" CommandParameter="{Binding}" ToolTip.Tip="Удалить">
<PathIcon Width="18" Height="18" Foreground="{DynamicResource PosDanger}"
Data="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>
@ -99,36 +102,36 @@
<TextBlock Grid.Row="3" Text="{Binding Message}" Foreground="{DynamicResource PosTextMuted}" Margin="4,10,0,0" FontSize="13.5"/>
</Grid>
<!-- ПРАВО: чек + оплата -->
<Border Grid.Column="1" Classes="card" Margin="10,18,20,18" Padding="20">
<Grid RowDefinitions="Auto,Auto,*,Auto">
<StackPanel Grid.Row="0" Spacing="10">
<!-- ПРАВО: чек + оплата (компактно, без пустот) -->
<Border Grid.Column="1" Classes="card" Margin="10,18,20,18" Padding="18">
<StackPanel Spacing="12">
<StackPanel Spacing="8">
<Grid ColumnDefinitions="*,Auto"><TextBlock Text="Позиций" Foreground="{DynamicResource PosTextMuted}" FontSize="15"/><TextBlock Grid.Column="1" Text="{Binding ItemCount}" Foreground="{DynamicResource PosText}" FontSize="15" FontWeight="Medium"/></Grid>
<Grid ColumnDefinitions="*,Auto"><TextBlock Text="Подытог" Foreground="{DynamicResource PosTextMuted}" FontSize="15"/><TextBlock Grid.Column="1" Text="{Binding Subtotal, StringFormat='{}{0:N0} ₸'}" Foreground="{DynamicResource PosText}" FontSize="15"/></Grid>
<Grid ColumnDefinitions="*,Auto" IsVisible="{Binding HasAnyDiscount}"><TextBlock Text="Скидка" Foreground="{DynamicResource PosTextMuted}" FontSize="15"/><TextBlock Grid.Column="1" Text="{Binding Discount, StringFormat='−{0:N0} ₸'}" Foreground="{DynamicResource PosBrand}" FontSize="15" FontWeight="Medium"/></Grid>
</StackPanel>
<Border Grid.Row="1" Background="{DynamicResource PosBrandSoft}" CornerRadius="12" Padding="16,14" Margin="0,16,0,0">
<Border Background="{DynamicResource PosBrandSoft}" CornerRadius="12" Padding="16,14">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Text="ИТОГО" Foreground="{DynamicResource PosText}" FontSize="18" FontWeight="SemiBold" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="{Binding Total, StringFormat='{}{0:N0} ₸'}" Foreground="{DynamicResource PosBrand}" FontSize="44" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Text="{Binding Total, StringFormat='{}{0:N0} ₸'}" Foreground="{DynamicResource PosBrand}" FontSize="42" FontWeight="Bold"/>
</Grid>
</Border>
<StackPanel Grid.Row="3" Spacing="10">
<Button Classes="pos primary" HorizontalAlignment="Stretch" Height="70" FontSize="22" Command="{Binding PayCommand}">
<Button Classes="pos primary" HorizontalAlignment="Stretch" Height="72" FontSize="22" Command="{Binding PayCommand}">
<TextBlock Text="Оплатить · F12" TextAlignment="Center"/>
</Button>
<Grid ColumnDefinitions="*,*">
<Button Classes="pos ghost" Margin="0,0,5,0" Content="Скидка"/>
<Button Grid.Column="1" Margin="5,0,0,0" Classes="pos ghost" Content="Отложить" Command="{Binding ParkCommand}"/>
</Grid>
<Grid ColumnDefinitions="*,*">
<Button Classes="pos ghost" Margin="0,0,5,0" Content="Отложенные" Command="{Binding ResumeCommand}"/>
<Button Grid.Column="1" Margin="5,0,0,0" Classes="pos danger" Content="Очистить" Command="{Binding ClearCommand}" ToolTip.Tip="Очистить чек (Esc)"/>
</Grid>
<!-- Вторичные действия: ровная сетка 2 колонки -->
<UniformGrid Columns="2">
<Button Classes="pos ghost" Margin="0,0,4,8" Content="Скидка"/>
<Button Classes="pos ghost" Margin="4,0,0,8" Content="Отложить · F7" Command="{Binding ParkCommand}"/>
<Button Classes="pos ghost" Margin="0,0,4,8" Content="Отложенные" Command="{Binding ResumeCommand}"/>
<Button Classes="pos ghost" Margin="4,0,0,8" Content="Возврат · F9" Command="{Binding GoReturnCommand}"/>
</UniformGrid>
<Button Classes="pos ghost" HorizontalAlignment="Stretch" Content="Внесение / Выплата · F10" Command="{Binding GoShiftCommand}"/>
<Button Classes="pos danger" HorizontalAlignment="Stretch" Content="Очистить · Esc" Command="{Binding ClearCommand}"/>
</StackPanel>
</Grid>
</Border>
</Grid>
</UserControl>