diff --git a/29WxOrderWpf/Common/DialogWindow.xaml.cs b/29WxOrderWpf/Common/DialogWindow.xaml.cs
index 4cfd2aa..b650996 100644
--- a/29WxOrderWpf/Common/DialogWindow.xaml.cs
+++ b/29WxOrderWpf/Common/DialogWindow.xaml.cs
@@ -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;
diff --git a/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs b/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs
index 1b0753e..58f7e0b 100644
--- a/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs
+++ b/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs
@@ -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
diff --git a/29WxOrderWpf/Ctrls/Statistics/Models/ShopRevenueStatisticsModels.cs b/29WxOrderWpf/Ctrls/Statistics/Models/ShopRevenueStatisticsModels.cs
index 6171f7f..3094804 100644
--- a/29WxOrderWpf/Ctrls/Statistics/Models/ShopRevenueStatisticsModels.cs
+++ b/29WxOrderWpf/Ctrls/Statistics/Models/ShopRevenueStatisticsModels.cs
@@ -1,6 +1,7 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
+using WPFCommon.Models;
namespace _29WxOrderWpf.Ctrls.Statistics.Models
{
diff --git a/29WxOrderWpf/Ctrls/Statistics/RevenueSummaryCards.xaml.cs b/29WxOrderWpf/Ctrls/Statistics/RevenueSummaryCards.xaml.cs
index 2a9dba2..b65ae3d 100644
--- a/29WxOrderWpf/Ctrls/Statistics/RevenueSummaryCards.xaml.cs
+++ b/29WxOrderWpf/Ctrls/Statistics/RevenueSummaryCards.xaml.cs
@@ -13,5 +13,6 @@ namespace _29WxOrderWpf.Ctrls.Statistics
{
InitializeComponent();
}
+
}
}
\ No newline at end of file
diff --git a/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml b/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml
index a01248e..6ab7470 100644
--- a/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml
+++ b/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml
@@ -1,4 +1,4 @@
-
-
+
@@ -119,7 +117,7 @@
-
+
@@ -348,4 +346,4 @@
-
+
diff --git a/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml.cs b/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml.cs
index 3da6c30..9bedc55 100644
--- a/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml.cs
+++ b/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml.cs
@@ -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 实现))。
///
- 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)
diff --git a/29WxOrderWpf/Ctrls/Statistics/ShowOrderDialogView.xaml b/29WxOrderWpf/Ctrls/Statistics/ShowOrderDialogView.xaml
index 6eb7118..460362c 100644
--- a/29WxOrderWpf/Ctrls/Statistics/ShowOrderDialogView.xaml
+++ b/29WxOrderWpf/Ctrls/Statistics/ShowOrderDialogView.xaml
@@ -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">
@@ -16,11 +18,34 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Data { get; set; }
+ public ObservableCollection Data { get; set; }
+ public ICollectionView DataView { get; private set; }
public ShowOrderDialogViewModel(List list)
{
- Data = list ?? new List();
+ Data = new ObservableCollection(list ?? new List());
+ 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();
+ 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()
+ .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;
}
}
diff --git a/29WxOrderWpf/Ctrls/Statistics/ViewModels/ShopRevenueStatisticsViewModel.cs b/29WxOrderWpf/Ctrls/Statistics/ViewModels/ShopRevenueStatisticsViewModel.cs
index 979a401..b2dc3cf 100644
--- a/29WxOrderWpf/Ctrls/Statistics/ViewModels/ShopRevenueStatisticsViewModel.cs
+++ b/29WxOrderWpf/Ctrls/Statistics/ViewModels/ShopRevenueStatisticsViewModel.cs
@@ -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 GetWindow;
}
}
\ No newline at end of file
diff --git a/29WxOrderWpf/ToolCtrls/ToastHelper.cs b/29WxOrderWpf/ToolCtrls/ToastHelper.cs
new file mode 100644
index 0000000..aa6f046
--- /dev/null
+++ b/29WxOrderWpf/ToolCtrls/ToastHelper.cs
@@ -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 }
+
+///
+/// 在指定 Window 内显示自动消失的提示框(Toast)
+/// 用法:ToastHelper.Show(window, "保存成功", ToastType.Success);
+///
+public static class ToastHelper
+{
+ // 每个 Window 对应一个提示容器,用于多个提示堆叠
+ private static readonly ConditionalWeakTable Hosts = new();
+ private static SolidColorBrush msgBrush;
+ static ToastHelper()
+ {
+ msgBrush = Application.Current.Resources["pageColorBrush"] as SolidColorBrush;
+ msgBrush = Application.Current.Resources["pageColorBrush"] as SolidColorBrush;
+ }
+ /// 要展示提示的窗口
+ /// 提示内容
+ /// 类型(决定背景色)
+ /// 停留时长(毫秒,不含淡入淡出)
+ 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
+ }
+ };
+ }
+
+ /// 覆盖在窗口内容上方的提示容器,顶部居中
+ 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;
+ }
+ }
+}
\ No newline at end of file