统计订单列表页 增加退款成功按钮

This commit is contained in:
chfei committed 2026-10-08 16:16:19 +08:00
1 parent 1ed9d72815
commit 87a0d34526
7 files changed
+135 -17

No files matched your search

@@ -200,6 +200,14 @@ namespace _29WxOrderWpf.Ctrls.Statistics.Models
/// </summary>
public class BuyerOrderInfo
{
/// <summary>
/// 买手订单ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 仓库类型 0,1直发
/// </summary>
public int PurchaseType { get; set; }
/// <summary>
/// 外部订单(买手订单)号
/// </summary>
@@ -210,6 +218,7 @@ namespace _29WxOrderWpf.Ctrls.Statistics.Models
/// </summary>
public int OutAmount { get; set; }
public long RefundId { get; set; }
/// <summary>
/// 退款金额(分)
/// </summary>
@@ -37,6 +37,12 @@ namespace _29WxOrderWpf.Ctrls.Statistics.Services
/// 订单明细列表(有效订单 / 退款订单 / 买手未退回金额的订单),供订单列表弹窗使用。
/// </summary>
Task<List<ShopOrderDetailResponse>> QueryOrderRowsAsync(ShopRevenueStatisticsQuery query, ShopOrderDetailType detailType);
/// <summary>
/// 把某笔买手订单标记为退款成功(订单列表弹窗“退款成功”按钮,仅买手未退回金额的订单使用)。
/// </summary>
/// <param name="id">买手退款表ID(<see cref="BuyerOrderInfo.RefundId"/>,即表格当前行的 id)</param>
Task<bool> UpdateBuyerRefundStatusAsync(long id);
}
/// <summary>
@@ -364,6 +370,9 @@ namespace _29WxOrderWpf.Ctrls.Statistics.Services
/// <summary>订单明细接口地址(订单列表弹窗用)</summary>
private const string GetShopOrderDetailsApi = "shop_revenue_statistics/GetShopOrderDetails";
/// <summary>更新买手订单退款状态接口地址(id 通过 URL 参数传递)</summary>
private const string UpdateBuyerRefundStatusApi = "buyer/UpdateBuyerRefundStatsu";
/// <summary>Unix 纪元(本地时区),用于解析以时间戳作为 Key 的返回数据</summary>
private static readonly DateTime UnixEpoch = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
@@ -626,5 +635,24 @@ namespace _29WxOrderWpf.Ctrls.Statistics.Services
EnsureSuccess(ret);
return ret.Data ?? new List<ShopOrderDetailResponse>();
}
/// <summary>
/// 请求 buyer/UpdateBuyerRefundStatsu 更新买手订单退款状态:
/// id 拼在 URL 查询参数上(Build29WxObjString 生成的地址已带 ?obj=…,这里用 &id= 追加);
/// 请求体走 UserLogin.GetSignPostData 常规签名(time/code 等)。
/// 返回码非 200 时抛出异常,由调用方提示。
/// </summary>
public async Task<bool> UpdateBuyerRefundStatusAsync(long id)
{
if (id == 0)
throw new Exception("更新失败:缺少买手订单ID");
var url = BaseClass.Build29WxObjString(UpdateBuyerRefundStatusApi) + "&id=" + id;
var html = await GetHtml.PostJsonAsync(url, UserLogin.GetSignPostData(new { }));
var ret = Deserialize<Result<bool>>(html);
EnsureSuccess(ret);
return ret.Data;
}
}
}
@@ -12,11 +12,12 @@
comn:DialogWindowProperty.Width="1320"
d:Background="White"
d:DesignHeight="450"
d:DesignWidth="800"
d:DesignWidth="1000"
Focusable="True"
PreviewKeyDown="ShowOrderDialogView_PreviewKeyDown"
mc:Ignorable="d">
<UserControl.Resources>
<wpf:BindingProxy x:Key="ViewModel" Data="{Binding}" />
<!-- 单元格文字居中 -->
<Style x:Key="CenterCellTextStyle" TargetType="TextBlock">
<Setter Property="TextAlignment" Value="Center" />
@@ -178,6 +179,27 @@
Binding="{Binding BuyerRefundStatusText}"
ElementStyle="{StaticResource CenterCellTextStyle}"
Header="退款状态" />
<!-- 操作:仅“买手未退回金额的订单”弹窗显示(列可见性在构造函数里按订单明细类型设置) -->
<DataGridTemplateColumn
x:Name="colUpdateRefund"
Width="*"
d:Visibility="Visible"
Header="操作"
Visibility="Collapsed">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding Source={StaticResource ViewModel}, Path=Data.UpdateBuyerRefundStatusCommand}"
CommandParameter="{Binding}"
Content="退款成功"
Style="{StaticResource BasePageButtonLightStyle}"
ToolTip="把该笔买手订单标记为退款成功" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
@@ -1,7 +1,10 @@
using _29WxOrderWpf.BaseWindows;
using _29WxOrderWpf.Commands;
using _29WxOrderWpf.Common;
using _29WxOrderWpf.Ctrls.Statistics.Models;
using _29WxOrderWpf.Ctrls.Statistics.Services;
using _29WxOrderWpf.ToolCtrls;
using NaiBa.Util.Extension;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -30,10 +33,14 @@ public partial class ShowOrderDialogView : UserControl
{
private readonly KeyEventHandler shortcutKeyHandler;
public ShowOrderDialogView(List<ShopOrderDetailResponse> list)
public ShowOrderDialogView(List<ShopOrderDetailResponse> list, ShopOrderDetailType detailType, IShopRevenueStatisticsService statisticsService)
{
InitializeComponent();
this.DataContext = new ShowOrderDialogViewModel(list);
this.DataContext = new ShowOrderDialogViewModel(list, statisticsService);
// “操作”列(退款成功按钮)只在“买手未退回金额的订单”弹窗里显示
if (detailType == ShopOrderDetailType.BuyerUnrefunded)
colUpdateRefund.Visibility = Visibility.Visible;
shortcutKeyHandler = ShowOrderDialogView_PreviewKeyDown;
@@ -83,6 +90,7 @@ public partial class ShowOrderDialogView : UserControl
}
}
/// <summary>
/// 弹窗级快捷键:Ctrl+A 全选(筛选后显示的)行,Ctrl+C 复制数据。
/// 焦点在文本框里(如订单号搜索框)时不拦截,保留文本自身的 Ctrl+A/Ctrl+C/Ctrl+V 行为。
@@ -139,7 +147,7 @@ public partial class ShowOrderDialogView : UserControl
/// 没有买手订单时占一行且买手字段为空),不把多笔买手订单合并到同一行。
/// 商铺订单级字段(店名/订单号/创建时间/金额等)在多行之间重复,保证每行都是一条完整记录。
/// </summary>
class ShopOrderDetailRow
class ShopOrderDetailRow : BindableBaseEx
{
public string ShopName { get; set; }
@@ -155,17 +163,28 @@ class ShopOrderDetailRow
public int UnrefundedAmount { get; set; }
/// <summary>买手订单表ID</summary>
public long BuyerId { get; set; }
/// <summary>买手(外部)订单号;无买手订单时为空</summary>
public string OutOrderSn { get; set; }
/// <summary>买手订单金额(分)</summary>
public int BuyerOutAmount { get; set; }
/// <summary>
/// 买手退款表 id
/// </summary>
public long BuyerRefundId { get; set; }
/// <summary>买手订单退款金额(分)</summary>
public int BuyerRefundAmount { get; set; }
/// <summary>买手订单退款状态</summary>
public string BuyerRefundStatusText { get; set; }
/// <summary>买手订单退款状态(更新成功后就地改为“退款成功”)</summary>
public string BuyerRefundStatusText
{
get => GetValue<string>();
set => SetValue(value);
}
/// <summary>把接口返回的订单明细按买手订单展平成表格行</summary>
public static List<ShopOrderDetailRow> Flatten(IEnumerable<ShopOrderDetailResponse> list)
@@ -202,7 +221,9 @@ class ShopOrderDetailRow
OrderRefundAmount = item.OrderRefundAmount,
OutAmount = item.OutAmount,
UnrefundedAmount = item.UnrefundedAmount,
BuyerId = buyerOrder == null ? 0 : buyerOrder.Id,
OutOrderSn = buyerOrder == null ? null : buyerOrder.OutOrderSn,
BuyerRefundId = buyerOrder == null ? 0 : buyerOrder.RefundId,
BuyerOutAmount = buyerOrder == null ? 0 : buyerOrder.OutAmount,
BuyerRefundAmount = buyerOrder == null ? 0 : buyerOrder.RefundAmount,
BuyerRefundStatusText = buyerOrder == null ? null : buyerOrder.RefundStatusText,
@@ -212,14 +233,17 @@ class ShopOrderDetailRow
class ShowOrderDialogViewModel : BindableBaseEx
{
private readonly IShopRevenueStatisticsService _statisticsService;
public ObservableCollection<ShopOrderDetailRow> Data { get; set; }
public ICollectionView DataView { get; private set; }
public ShowOrderDialogViewModel(List<ShopOrderDetailResponse> list)
public ShowOrderDialogViewModel(List<ShopOrderDetailResponse> list, IShopRevenueStatisticsService statisticsService)
{
// 按买手订单展平:一笔买手订单一一行,不合并
Data = new ObservableCollection<ShopOrderDetailRow>(ShopOrderDetailRow.Flatten(list));
DataView = CollectionViewSource.GetDefaultView(Data);
DataView.Filter = FilterRow;
_statisticsService = statisticsService;
}
private bool FilterRow(object obj)
@@ -258,13 +282,9 @@ class ShowOrderDialogViewModel : BindableBaseEx
list = GetFilteredRows();
}
Window window = Application.Current.Windows
.OfType<Window>()
.FirstOrDefault(w => w.IsActive) ?? Application.Current.MainWindow;
if (list.Count == 0)
{
ToastHelper.Show(window, "没有可复制的数据", type: ToastType.Warning);
ToastHelper.Show("没有可复制的数据", type: ToastType.Warning);
return;
}
@@ -272,11 +292,43 @@ class ShowOrderDialogViewModel : BindableBaseEx
{
string text = BuildCopyText(list);
Application.Current.Dispatcher.Invoke(() => Clipboard.SetText(text));
ToastHelper.Show(window, "复制成功");
ToastHelper.Show("复制成功");
}
catch (Exception ex)
{
ToastHelper.Show(window, "复制失败 " + ex.Message, type: ToastType.Error);
ToastHelper.Show("复制失败 " + ex.Message, type: ToastType.Error);
}
}
public ICommand UpdateBuyerRefundStatusCommand => new AsyncDelegateCommand<ShopOrderDetailRow>(UpdateBuyerRefundStatus);
private async Task UpdateBuyerRefundStatus(ShopOrderDetailRow row)
{
if (row.BuyerRefundId == 0)
{
ToastHelper.Show("该行缺少买手订单ID,无法更新", type: ToastType.Warning);
return;
}
try
{
var ret = await _statisticsService.UpdateBuyerRefundStatusAsync(row.BuyerRefundId);
if (ret)
{
row.BuyerRefundStatusText = "退款成功";
ToastHelper.Show("操作成功");
}
else
throw new Exception("状态更改失败");
}
catch (Exception ex)
{
ToastHelper.Show("操作失败 " + ex.Message, type: ToastType.Error);
}
finally
{
}
}
@@ -613,7 +613,7 @@ namespace _29WxOrderWpf.Ctrls.Statistics.ViewModels
new DialogWindow()
{
Title = "订单列表",
Content = new ShowOrderDialogView(showList),
Content = new ShowOrderDialogView(showList, detailType, _service),
DataContext = showList
}.ShowDialog();
}
@@ -359,7 +359,7 @@ namespace _29WxOrderWpf.Ctrls.Statistics.ViewModels
new DialogWindow(GetWindow())
{
Title = "订单列表",
Content = new ShowOrderDialogView(showList),
Content = new ShowOrderDialogView(showList, detailType, _service),
DataContext = showList
}.Show();
}
+8 -1
View File
@@ -93,7 +93,14 @@ public static class ToastHelper
};
toast.BeginAnimation(UIElement.OpacityProperty, anim);
}
public static void Show(string message,
ToastType type = ToastType.Info, int durationMs = 2000)
{
Window window = Application.Current.Windows
.OfType<Window>()
.FirstOrDefault(w => w.IsActive) ?? Application.Current.MainWindow;
Show(window, message, type, durationMs);
}
private static Border CreateToast(string message, ToastType type)
{
var color = type switch