增加 统计页面订单列表 搜索,复制表格。window层级
增加 toast提示 可以作用域任何window
This commit is contained in:
1 parent
b1e03ddbb1
commit
03f71a5d64
10 files changed
+286
-27
No files matched your search
@@ -19,10 +19,10 @@ namespace _29WxOrderWpf.Common
|
||||
private readonly Style dialogWindowStyle;
|
||||
private bool isConstructorSuccessful = false;
|
||||
private UserControl _content;
|
||||
public DialogWindow()
|
||||
public DialogWindow(Window owner = null)
|
||||
{
|
||||
InitializeComponent();
|
||||
Owner = Application.Current.MainWindow;
|
||||
Owner = owner ?? Application.Current.MainWindow;
|
||||
isConstructorSuccessful = true;
|
||||
dialogWindowStyle = (Style)TryFindResource("DialogWindowStyle");
|
||||
Loaded += DialogWindow_Loaded;
|
||||
|
||||
@@ -22,22 +22,18 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls;
|
||||
public partial class OrderListCtrl
|
||||
{
|
||||
#region 统计
|
||||
private DialogWindow _statisticsDialog;
|
||||
private ShopRevenueStatisticsView _statisticsDialog;
|
||||
public ICommand ShowShopRevenueStatisticsDialogViewCommand => new DelegateCommand(ShowShopRevenueStatisticsDialogView);
|
||||
|
||||
private void ShowShopRevenueStatisticsDialogView()
|
||||
{
|
||||
if (_statisticsDialog == null)
|
||||
{
|
||||
_statisticsDialog = new DialogWindow()
|
||||
{
|
||||
Title = "统计",
|
||||
Content = new ShopRevenueStatisticsView(),
|
||||
|
||||
};
|
||||
_statisticsDialog =new ShopRevenueStatisticsView();
|
||||
_statisticsDialog.Closed += (s, e) => _statisticsDialog = null;
|
||||
}
|
||||
_statisticsDialog.Show();
|
||||
_statisticsDialog.Activate();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using WPFCommon.Models;
|
||||
|
||||
namespace _29WxOrderWpf.Ctrls.Statistics.Models
|
||||
{
|
||||
|
||||
@@ -13,5 +13,6 @@ namespace _29WxOrderWpf.Ctrls.Statistics
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<UserControl
|
||||
<Window
|
||||
x:Class="_29WxOrderWpf.Ctrls.Statistics.ShopRevenueStatisticsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -13,10 +13,8 @@
|
||||
IsDesignTimeCreatable=True}"
|
||||
d:DesignHeight="900"
|
||||
d:DesignWidth="1600"
|
||||
wpf:DialogWindowProperty.ResizeMode="CanResizeWithGrip"
|
||||
wpf:DialogWindowProperty.ShowMinButton="False"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<Window.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="boolToVisibilityConverter" />
|
||||
|
||||
<!-- 卡片样式(白底、圆角、阴影) -->
|
||||
@@ -119,7 +117,7 @@
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="#F5F7FB">
|
||||
<TabControl SelectionChanged="TabControl_SelectionChanged" Style="{StaticResource StatisticsTabControlStyle}">
|
||||
@@ -348,4 +346,4 @@
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</Window>
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Windows.Controls;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using _29WxOrderWpf.Ctrls.Statistics.ViewModels;
|
||||
|
||||
namespace _29WxOrderWpf.Ctrls.Statistics
|
||||
@@ -9,7 +10,7 @@ namespace _29WxOrderWpf.Ctrls.Statistics
|
||||
/// 如需注入自定义数据服务,请使用
|
||||
/// new ShopRevenueStatisticsView(new ShopRevenueStatisticsViewModel(你的 IShopRevenueStatisticsService 实现))。
|
||||
/// </summary>
|
||||
public partial class ShopRevenueStatisticsView : UserControl
|
||||
public partial class ShopRevenueStatisticsView : Window
|
||||
{
|
||||
public ShopRevenueStatisticsView()
|
||||
: this(new ShopRevenueStatisticsViewModel())
|
||||
@@ -19,7 +20,9 @@ namespace _29WxOrderWpf.Ctrls.Statistics
|
||||
public ShopRevenueStatisticsView(ShopRevenueStatisticsViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
viewModel.GetWindow = () => this;
|
||||
DataContext = viewModel;
|
||||
|
||||
}
|
||||
|
||||
private void help_mouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:_29WxOrderWpf.Ctrls.Statistics"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:wpf="WPFCommon"
|
||||
d:Background="White"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
Focusable="True"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<!-- 单元格文字居中 -->
|
||||
@@ -16,11 +18,34 @@
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Border
|
||||
Grid.Row="0"
|
||||
Padding="10"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="0,0,0,1">
|
||||
<wpf:SpacingStackPanel HorizontalSpacing="10" Orientation="Horizontal">
|
||||
<wpf:TitleContent
|
||||
Title="订单号:"
|
||||
Width="180"
|
||||
Placement="Left"
|
||||
TitleVerticalAlignment="Center">
|
||||
<TextBox Height="22" Text="{Binding OrderId, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</wpf:TitleContent>
|
||||
<Button
|
||||
Command="{Binding SelectAllCommand}"
|
||||
Content="复制数据"
|
||||
Style="{StaticResource BaseButtonLightStyle}" />
|
||||
</wpf:SpacingStackPanel>
|
||||
</Border>
|
||||
<DataGrid
|
||||
Grid.Row="1"
|
||||
d:ItemsSource="{d:SampleData ItemCount=10}"
|
||||
AlternatingRowBackground="#FAFAFA"
|
||||
AutoGenerateColumns="False"
|
||||
@@ -35,11 +60,16 @@
|
||||
HeadersVisibility="Column"
|
||||
HorizontalGridLinesBrush="#EEEEEE"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding Data}"
|
||||
ItemsSource="{Binding DataView}"
|
||||
RowHeight="44"
|
||||
SelectionMode="Single"
|
||||
SelectionUnit="FullRow"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<!-- 店名 -->
|
||||
<DataGridTextColumn
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using _29WxOrderWpf.BaseWindows;
|
||||
using _29WxOrderWpf.Commands;
|
||||
using _29WxOrderWpf.Ctrls.Statistics.Models;
|
||||
using _29WxOrderWpf.ToolCtrls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -14,6 +18,7 @@ using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using WPFCommon.Models;
|
||||
|
||||
namespace _29WxOrderWpf.Ctrls.Statistics;
|
||||
|
||||
@@ -41,20 +46,83 @@ public partial class ShowOrderDialogView : UserControl
|
||||
try
|
||||
{
|
||||
Clipboard.SetDataObject(row.OrderId);
|
||||
BaseMsgWindow.ShowAnimateMessage("复制成功");
|
||||
ToastHelper.Show(window, "复制成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
BaseMsgWindow.ShowError("复制失败 " + ex.Message,window: window);
|
||||
ToastHelper.Show(window, "复制失败 " + ex.Message, type: ToastType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class ShowOrderDialogViewModel
|
||||
class ShowOrderDialogViewModel : BindableBaseEx
|
||||
{
|
||||
public List<ShopRevenueStatisticsRow> Data { get; set; }
|
||||
public ObservableCollection<ShopRevenueStatisticsRow> Data { get; set; }
|
||||
public ICollectionView DataView { get; private set; }
|
||||
public ShowOrderDialogViewModel(List<ShopRevenueStatisticsRow> list)
|
||||
{
|
||||
Data = list ?? new List<ShopRevenueStatisticsRow>();
|
||||
Data = new ObservableCollection<ShopRevenueStatisticsRow>(list ?? new List<ShopRevenueStatisticsRow>());
|
||||
DataView = CollectionViewSource.GetDefaultView(Data);
|
||||
DataView.Filter = FilterRow;
|
||||
}
|
||||
|
||||
private bool FilterRow(object obj)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(OrderId))
|
||||
return true;
|
||||
if (obj is ShopRevenueStatisticsRow row)
|
||||
{
|
||||
return row.OrderId.Contains(OrderId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public string OrderId
|
||||
{
|
||||
get => GetValue<string>();
|
||||
set => SetValue(value, () => DataView.Refresh());
|
||||
}
|
||||
|
||||
public ICommand SelectAllCommand => new DelegateCommand(SelectAll);
|
||||
|
||||
private void SelectAll()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
// 表头
|
||||
sb.AppendLine("店名\t订单\t金额\t退款金额\t外采金额");
|
||||
|
||||
// 数据行
|
||||
foreach (var item in Data)
|
||||
{
|
||||
string shopName = CsvEscape(item.ShopName);
|
||||
string orderId = item.OrderId;
|
||||
string orderPrice = (item.OrderPrice / 100m).ToString("0.00");
|
||||
string refundAmount = (item.RefundAmount / 100m).ToString("0.00");
|
||||
string outAmount = (item.OutAmount / 100m).ToString("0.00");
|
||||
|
||||
sb.AppendLine($"{shopName}\t{orderId}\t{orderPrice}\t{refundAmount}\t{outAmount}");
|
||||
}
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() => Clipboard.SetText(sb.ToString()));
|
||||
var window = Application.Current.Windows
|
||||
.OfType<Window>()
|
||||
.FirstOrDefault(w => w.IsActive) ?? Application.Current.MainWindow;
|
||||
|
||||
ToastHelper.Show(window, "复制成功");
|
||||
}
|
||||
|
||||
private string CsvEscape(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return "";
|
||||
|
||||
// 含逗号、引号、换行时,用双引号包起来,内部引号翻倍
|
||||
if (value.Contains(',') || value.Contains('"') || value.Contains('\n') || value.Contains('\r'))
|
||||
{
|
||||
return "\"" + value.Replace("\"", "\"\"") + "\"";
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace _29WxOrderWpf.Ctrls.Statistics.ViewModels
|
||||
@@ -330,13 +331,13 @@ namespace _29WxOrderWpf.Ctrls.Statistics.ViewModels
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
new DialogWindow()
|
||||
new DialogWindow(GetWindow())
|
||||
{
|
||||
Title="订单列表",
|
||||
Content = new ShowOrderDialogView(showList),
|
||||
DataContext = rows
|
||||
}.ShowDialog();
|
||||
}.Show();
|
||||
}
|
||||
public Func<Window> GetWindow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Media.Effects;
|
||||
|
||||
namespace _29WxOrderWpf.ToolCtrls;
|
||||
|
||||
public enum ToastType { Info, Success, Warning, Error }
|
||||
|
||||
/// <summary>
|
||||
/// 在指定 Window 内显示自动消失的提示框(Toast)
|
||||
/// 用法:ToastHelper.Show(window, "保存成功", ToastType.Success);
|
||||
/// </summary>
|
||||
public static class ToastHelper
|
||||
{
|
||||
// 每个 Window 对应一个提示容器,用于多个提示堆叠
|
||||
private static readonly ConditionalWeakTable<Window, ToastAdorner> Hosts = new();
|
||||
private static SolidColorBrush msgBrush;
|
||||
static ToastHelper()
|
||||
{
|
||||
msgBrush = Application.Current.Resources["pageColorBrush"] as SolidColorBrush;
|
||||
msgBrush = Application.Current.Resources["pageColorBrush"] as SolidColorBrush;
|
||||
}
|
||||
/// <param name="owner">要展示提示的窗口</param>
|
||||
/// <param name="message">提示内容</param>
|
||||
/// <param name="type">类型(决定背景色)</param>
|
||||
/// <param name="durationMs">停留时长(毫秒,不含淡入淡出)</param>
|
||||
public static void Show(Window owner, string message,
|
||||
ToastType type = ToastType.Info, int durationMs = 2000)
|
||||
{
|
||||
if (owner == null || string.IsNullOrEmpty(message)) return;
|
||||
|
||||
// 允许在非 UI 线程调用
|
||||
if (!owner.Dispatcher.CheckAccess())
|
||||
{
|
||||
owner.Dispatcher.BeginInvoke(new Action(() => Show(owner, message, type, durationMs)));
|
||||
return;
|
||||
}
|
||||
|
||||
// 窗口还没加载完,等加载后再显示
|
||||
if (!owner.IsLoaded)
|
||||
{
|
||||
RoutedEventHandler handler = null;
|
||||
handler = (s, e) =>
|
||||
{
|
||||
owner.Loaded -= handler;
|
||||
Show(owner, message, type, durationMs);
|
||||
};
|
||||
owner.Loaded += handler;
|
||||
return;
|
||||
}
|
||||
|
||||
if (owner.Content is not UIElement content) return;
|
||||
var layer = AdornerLayer.GetAdornerLayer(content);
|
||||
if (layer == null) return;
|
||||
|
||||
if (!Hosts.TryGetValue(owner, out var host))
|
||||
{
|
||||
host = new ToastAdorner(content);
|
||||
layer.Add(host);
|
||||
Hosts.Add(owner, host);
|
||||
}
|
||||
|
||||
var toast = CreateToast(message, type);
|
||||
host.Panel.Children.Add(toast);
|
||||
|
||||
// 淡入 -> 停留 -> 淡出
|
||||
var fadeIn = TimeSpan.FromMilliseconds(250);
|
||||
var fadeOut = TimeSpan.FromMilliseconds(400);
|
||||
var hold = TimeSpan.FromMilliseconds(Math.Max(durationMs, 0));
|
||||
|
||||
var anim = new DoubleAnimationUsingKeyFrames();
|
||||
anim.KeyFrames.Add(new LinearDoubleKeyFrame(0, TimeSpan.Zero));
|
||||
anim.KeyFrames.Add(new LinearDoubleKeyFrame(1, fadeIn));
|
||||
anim.KeyFrames.Add(new LinearDoubleKeyFrame(1, fadeIn + hold));
|
||||
anim.KeyFrames.Add(new LinearDoubleKeyFrame(0, fadeIn + hold + fadeOut));
|
||||
anim.Completed += (s, e) =>
|
||||
{
|
||||
host.Panel.Children.Remove(toast);
|
||||
if (host.Panel.Children.Count == 0)
|
||||
{
|
||||
layer.Remove(host);
|
||||
Hosts.Remove(owner);
|
||||
}
|
||||
};
|
||||
toast.BeginAnimation(UIElement.OpacityProperty, anim);
|
||||
}
|
||||
|
||||
private static Border CreateToast(string message, ToastType type)
|
||||
{
|
||||
var color = type switch
|
||||
{
|
||||
ToastType.Success => Color.FromRgb(0x2E, 0x9E, 0x5B),
|
||||
ToastType.Warning => Color.FromRgb(0xE6, 0x9A, 0x1A),
|
||||
ToastType.Error => Color.FromRgb(0xD9, 0x4A, 0x4A),
|
||||
_ => msgBrush.Color,//Color.FromRgb(0x40, 0x40, 0x40),
|
||||
};
|
||||
|
||||
return new Border
|
||||
{
|
||||
Background = new SolidColorBrush(color),
|
||||
CornerRadius = new CornerRadius(6),
|
||||
Padding = new Thickness(18, 10, 18, 10),
|
||||
Margin = new Thickness(0, 0, 0, 8),
|
||||
Opacity = 0,
|
||||
MaxWidth = 480,
|
||||
Effect = new DropShadowEffect
|
||||
{
|
||||
BlurRadius = 12,
|
||||
ShadowDepth = 2,
|
||||
Opacity = 0.3,
|
||||
Color = Colors.Black
|
||||
},
|
||||
Child = new TextBlock
|
||||
{
|
||||
Text = message,
|
||||
Foreground = Brushes.White,
|
||||
FontSize = 14,
|
||||
TextWrapping = TextWrapping.Wrap
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>覆盖在窗口内容上方的提示容器,顶部居中</summary>
|
||||
private sealed class ToastAdorner : Adorner
|
||||
{
|
||||
public StackPanel Panel { get; }
|
||||
|
||||
public ToastAdorner(UIElement adornedElement) : base(adornedElement)
|
||||
{
|
||||
IsHitTestVisible = false; // 不拦截鼠标事件
|
||||
Panel = new StackPanel { Orientation = Orientation.Vertical };
|
||||
AddVisualChild(Panel);
|
||||
}
|
||||
|
||||
protected override int VisualChildrenCount => 1;
|
||||
protected override Visual GetVisualChild(int index) => Panel;
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
Panel.Measure(constraint);
|
||||
return AdornedElement.RenderSize;
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
var size = Panel.DesiredSize;
|
||||
double x = (finalSize.Width - size.Width) / 2;
|
||||
Panel.Arrange(new Rect(new Point(Math.Max(x, 0), 30), size)); // 距顶部 30
|
||||
return finalSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user